POJ3163 King of Fighters 状压DP/费用流

版权声明:不转不是中国人!(滑稽) https://blog.csdn.net/xym_CSDN/article/details/80847391

回归后的第一篇blog,康复打板中
这种题我做了2个多小时。。(反正我现在已经失去对题目难度的辨识了)
很容易想到 O ( m n 2 n ) 的状压做法,但是超时,考虑优化,想到不正确的贪心思路,即n轮中每次都取最大概率,而最优解中不一定取这次的最大概率,但是会“退而求其次”,找没被选的里面的最优,而被选的最多为n-1个,所以对于每轮来说只要挑出概率前 n 大的,最优解一定在其中选择,这样数据规模就从 m 减小到了至多 n 2
除此以外,对数据取log后变为求累加的最大值,所以也可以建图后费用流
注意:数据给出的是对手获胜的概率,不是自己的
状压DP

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ID,cnt;
int bit[1030],id[100005];
double data[11][100005],a[11][105],f[2][1030];
bool vis[100005];
bool cmp(int x,int y){return data[ID][x]>data[ID][y];}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for (int i=1;i<=n;++i)
            for (int j=1;j<=m;++j) scanf("%lf",data[i]+j),data[i][j]=1.0-data[i][j];
        for (int j=1,i=1;i<(1<<n);i<<=1,++j) bit[i]=j;
        for (int j=1;j<=m;++j) id[j]=j,vis[j]=0;
        cnt=0;
        for (ID=1;ID<=n;++ID)
        {
            sort(id+1,id+m+1,cmp);
            for (int j=1;j<=n;++j)
                if (!vis[id[j]])
                {
                    vis[id[j]]=1;
                    ++cnt;
                    for (int k=1;k<=n;++k) a[k][cnt]=data[k][id[j]];
                }
        }
        for (int i=0;i<(1<<n);++i) f[0][i]=0;
        f[0][0]=1;
        for (int x=1,i=1;i<=cnt;++i,x^=1)
            for (int k,j=0;j<(1<<n);++j)
            {
                f[x][j]=f[x^1][j];
                for (k=j;k;k^=(k&-k))
                    f[x][j]=max(f[x][j],f[x^1][j^(k&-k)]*a[bit[k&-k]][i]);
            }
        printf("%.15lf\n",f[cnt&1][(1<<n)-1]);
    }
}

费用流

#include<cstdio>
#include<iostream>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,ID,cnt,S,T,tot;
int id[100005],up[205],first[205];
double data[11][100005],a[11][105],dis[205];
bool vis[100005];
bool cmp(int x,int y){return data[ID][x]>data[ID][y];}
struct edge{
    int v,next;
    char w;
    double c;
}e[10005];
void add(int x,int y,int z,double c)
{
    e[++tot].v=y;e[tot].next=first[x];e[tot].w=z;e[tot].c=c;first[x]=tot;
    e[++tot].v=x;e[tot].next=first[y];e[tot].w=0;e[tot].c=-c;first[y]=tot;
}
queue<int>q;
bool spfa()
{
    for (int i=1;i<=T;++i) dis[i]=1e9;
    q.push(S);vis[S]=1;
    for (int x;!q.empty();q.pop())
    {
        x=q.front();
        for (int i=first[x];i;i=e[i].next)
            if (e[i].w&&dis[e[i].v]>dis[x]+e[i].c)
            {
                dis[e[i].v]=dis[x]+e[i].c;
                up[e[i].v]=i;
                if (!vis[e[i].v])
                    q.push(e[i].v),
                    vis[e[i].v]=1;
            }
        vis[x]=0;
    }
    return dis[T]<1e8;
}
double flow()
{
    for (int i=up[T];i;i=up[e[i^1].v]) swap(e[i].w,e[i^1].w);
    return dis[T];
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for (int i=1;i<=n;++i)
            for (int j=1;j<=m;++j) scanf("%lf",data[i]+j),data[i][j]=1.0-data[i][j];
        for (int j=1;j<=m;++j) id[j]=j,vis[j]=0;
        cnt=0;
        for (ID=1;ID<=n;++ID)
        {
            sort(id+1,id+m+1,cmp);
            for (int j=1;j<=n;++j)
                if (!vis[id[j]])
                {
                    vis[id[j]]=1;
                    ++cnt;
                    for (int k=1;k<=n;++k) a[k][cnt]=data[k][id[j]];
                }
        }
        S=0;T=n+cnt+1;tot=1;
        for (int i=S;i<=T;++i) vis[i]=first[i]=0;
        for (int i=1;i<=n;++i) add(S,i,1,0);
        for (int i=1;i<=cnt;++i) add(i+n,T,1,0);
        for (int i=1;i<=n;++i)
            for (int j=1;j<=cnt;++j) add(i,j+n,1,-log(a[i][j]));
        double ans=0;
        while(spfa()) ans+=flow();
        printf("%.15lf\n",exp(-ans));
    }
}

猜你喜欢

转载自blog.csdn.net/xym_CSDN/article/details/80847391