ZOJ3471

来源:互联网 发布:解放军的无人机 知乎 编辑:程序博客网 时间:2024/06/07 22:04

ZOJ3471 Most Powerful

有n个原子,任意两个原子互相撞击会产生一定的能量,并且被撞击的那个会消失,然后要你求当n个原子发生了n-1次撞击后能产生的最大能量.

输入:包含多组实例.每个实例的第一行是N(2<=N<=10),然后接下来N行,每行有N个整数x(0<=x<=1000),第i行的第j个数,表示i原子撞击j原子后产生的能量,且j消失.当N为0时表输入结束.

输出:对于每个实例输出能量最大值.

分析:本题和TSP问题很相似,使用类似的状态定义方式解即可.

令d[i][S]表示当前在原子i且已经用过的原子集合为S(S包括i)时,能产生的最大能量.

状态转移方程是:d[i][S|(1<<i)]=max{ d[j][S]+v[i][j] },用i去撞j,或d[j][S|(1<<i)]=max{d[j][S]+v[j][i] },用j去撞i

初值:d[i][1<<i]=0.

这么做此题就是错的.题意理解有偏差:本题的意思是任意两个原子都可以相撞,并不一定是要依次相撞.比如6个原子,现在123原子已经撞了剩下3号原子,接下来我可以用5和6撞,然后再用剩下的去撞3,而并不一定需要用3去撞{4,5,6}中的一个.所以正确的解法应该是:

令d[S]=x表示当前集合S中表示的原子已经销毁了,能产生的最大能量值.

d[S+{j}]=max{ d[S]+v[i][j] },i与j都是集合S外的原子且用i撞j.

d[S+{i}]=max{ d[S]+v[j][i] },i与j都是集合S外的原子且用j撞i.

AC代码:30ms

#include<cstring>#include<cstdio>#include<algorithm>using namespace std;int n;int v[15][15];int d[1<<10];int main(){    while(scanf("%d",&n)==1&&n)    {        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)                scanf("%d",&v[i][j]);        memset(d,-1,sizeof(d));        d[0]=0;        for(int i=0;i<n;i++)            for(int j=0;j<n;j++)if(i!=j)//用j撞i销毁i                d[(1<<i)]=max( d[(1<<i)] , v[j][i] );        int ans = 0;        for(int S=0;S<(1<<n);S++)//枚举所有子状态        {            for(int i=0;i<n;i++)if( !(S&(1<<i)) && d[S]!=-1)//i不在S中            {                for(int j=0;j<n;j++)if(j!=i && !(S&(1<<j)))//j不在S中,从j到i或从i到j                {                    d[S|(1<<i)] = max(d[S|(1<<i)],d[S]+v[j][i]);//从j到i,废弃i                    d[S|(1<<j)] = max(d[S|(1<<j)],d[S]+v[i][j]);//从i到j,废弃j                    ans = max(ans,max(d[S|(1<<j)],d[S|(1<<i)]));                }            }        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击