Most Powerful ZOJ - 3471(状压dp)

Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappears and a lot of power is produced. Researchers know the way every two atoms perform when collided and the power every two atoms can produce.

You are to write a program to make it most powerful, which means that the sum of power produced during all the collides is maximal.

Input
There are multiple cases. The first line of each case has an integer N (2 <= N <= 10), which means there are N atoms: A1, A2, … , AN. Then N lines follow. There are N integers in each line. The j-th integer on the i-th line is the power produced when Ai and Aj collide with Aj gone. All integers are positive and not larger than 10000.

The last case is followed by a 0 in one line.

There will be no more than 500 cases including no more than 50 large cases that N is 10.

Output
Output the maximal power these N atoms can produce in a line for each case.

Sample Input
2
0 4
1 0
3
0 20 1
12 0 1
1 10 0
0

Sample Output
4
22

题意:
n个原子碰撞,被撞的那个消失,并且产生一部分能量。
求发生n-1次碰撞后的最大能量。
思路:
如果碰撞是顺序发生,就可以看做有权无向图上的TSP问题。
但是碰撞任意发生,意味着1可以先和2碰,再3和4碰,两者剩下的再发生碰撞,这就不符合TSP问题的顺序性了。

那么定义dp(s),s为二进制状态,代表当前有多少原子已经被撞了。
那么转移的话枚举没在s集和里的原子进行碰撞

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int a[15][15];
int f[1 << 15];
int main()
{
    int n;
    while(~scanf("%d",&n) && n)
    {
        for(int i = 1;i <= n;i++)
        {
            for(int j = 1;j <= n;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        
        memset(f,-1,sizeof(f));
        f[0] = 0;
        for(int i = 1;i <= n;i++)
        {
            for(int j = 1;j <= n;j++)
            {
                if(i != j)
                    f[1 << (i - 1)] = max(f[1 << (i - 1)], a[j][i]);
            }
        }
        
        int ans = 0;

        for(int s = 0;s < (1 << n);s++)
        {
            for(int i = 1;i <= n;i++)
            {
                if((s & (1 << (i - 1))) == 0)
                {
                    for(int j = 1;j <= n;j++)
                    {
                        if((s & (1 << (j - 1))) == 0 && i != j && f[s] != -1)
                        {
                            f[s | (1 << (j - 1))] = max(f[s | (1 << (j - 1))],f[s] + a[i][j]);//i撞j,j消失
                            f[s | (1 << (i - 1))] = max(f[s | (1 << (i - 1))],f[s] + a[j][i]);//j撞i,i消失
                        }
                    }
                }
            }
        }
        
        for(int i = 0;i < ( 1 << n );i++)
        {
            ans = max(ans,f[i]);
        }
        
        printf("%d\n",ans);
    }
    return 0;
}

发布了628 篇原创文章 · 获赞 17 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/103990604