poj 2288 状态压缩~最优值+方案数

来源:互联网 发布:安卓手机安装linux 编辑:程序博客网 时间:2024/05/18 01:28

题目并不难,用三维分别表示最后一个节点,倒数第二个节点以及经过的点集,然后直接往后递推,方案数统计的时候不知道有没有重边,直接开二位数组记录边数,方案数会超int。


ACcode:

#include<cstdio>#include<cstring>typedef long long LL;int const NS=13;int n,m;int v[NS];int dp[NS][NS][1<<NS];int g[NS][NS],b[NS];int pos[1<<NS][NS+1];LL num[NS][NS][1<<NS];void prepare(){    int t,lim=(1<<NS);    for (int i=0;i<NS;i++)    b[i]=1<<i;    for (int i=0;i<lim;i++)    {        t=0;        for (int x=i,j=0;x>0;x>>=1,j++)        if (x&1) pos[i][++t]=j;        pos[i][0]=t;    }}int main(){    int w,ans;    LL res;    int x,y,z,t,lim,cas;    prepare();    scanf("%d",&cas);    while (cas--)    {        scanf("%d%d",&n,&m);        memset(g,0,sizeof(g));        memset(dp,-1,sizeof(dp));        memset(num,0,sizeof(num));        for (int i=0;i<n;i++)        scanf("%d",&v[i]);        for (int i=0;i<m;i++)        {            scanf("%d%d",&x,&y);            --x,--y;            g[x][y]++,g[y][x]++;        }        lim=1<<n;        for (int i=0;i<n;i++)        for (int j=0;j<n;j++)        {            if (g[i][j])            {                dp[j][i][b[i]|b[j]]=v[i]*v[j];                num[j][i][b[i]|b[j]]=g[j][i];            }        }        for (int i=3;i<lim;i++)        {            if (pos[i][0]<2) continue;            for (int j=1;j<=pos[i][0];j++)            {                x=pos[i][j],y=i-b[x];                for (int k=1;k<=pos[y][0];k++)                {                    z=pos[y][k];                    for (int u=0;u<n;u++)                    {                        if (g[x][u])                        {                            t=i|b[u];                            if (t==i||dp[x][z][i]==-1) continue;                            w=dp[x][z][i]+v[x]*v[u];                            if (g[z][u]) w+=v[x]*v[z]*v[u];                            if (dp[u][x][t]<w)                            {                                dp[u][x][t]=w;                                num[u][x][t]=num[x][z][i]*g[x][u];                            }                            else if (dp[u][x][t]==w)                            num[u][x][t]+=num[x][z][i]*g[x][u];                        }                    }                }            }        }        ans=res=0,lim--;        for (int i=0;i<n;i++)        for (int j=0;j<n;j++)        {            w=dp[i][j][lim];            if (w>ans)            ans=w,res=num[i][j][lim];            else if (w==ans)            res+=num[i][j][lim];        }        if (n==1) ans=v[0],res=2;        else if (ans)        for (int i=0;i<n;i++)        ans+=v[i];        printf("%d %I64d\n",ans,res/2);    }    return 0;}


原创粉丝点击