hdu 检测赛 Problem C(状压dp)

Problem C

Problem Description

新年伊始,集训队迎来了15级新生。教练打算将大家N(2<=N<=20)个人分成AB两队,已知每两个新生之间都有相互的思念值,如果分到一队的话经常见面不会思念,但是如果不被分到一队的话,他们就会无比思念对方,此时两个人之间的思念值为f(0<=f<=10000),教练想知道,分队使大家的思念值总和(即A队的每个人与B队的每个人之间的思念值的总和)达到的最大值是多少。PS:两个人如果在不同队伍才加入思念值总和

Input

多组用例,处理到EOF
对于每组用例:
第一行 N
接下来的N行,每行N个数
第i行第j个数表示i和j分到两个队时彼此的思念值
第i行第j个数等于第j行第i个数,当i=j时,思念值为0

Output

思念值总值的最大值

Sample Input

3
0 50 30
50 0 40
30 40 0

Sample Output

90
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int o[1<<20];
int a[24][24];
int d[24];
int sum;
int f[1<<20];
int b[24];
void solve()
{
    int lost=sum;
    int top=1<<n;//上限
    f[0]=sum;//初始所有人都在groupA
    for(int i=1;i<top;++i)
    {
        int x=i;
        int num=0;
        while(x)//取出i的2进制中所有为1的部分
        {
            int y=o[x&-x];
            x-=x&-x;
            b[++num]=y;
        }
        f[i]=f[i-(1<<b[1])];//i的2进制最低位1在的位置被加入groupB
        int tmp=0;
        for(int j=2;j<=num;++j)
            tmp+=a[b[1]][b[j]];//记录当前b[1]与groupA成员的相互思念值
        f[i]+=tmp-(d[b[1]]-tmp);//更新思念值
        lost=min(lost,f[i]);//更新lost
    }
    printf("%d\n",sum-lost);
}
int main()
{
    for(int i=0;i<20;++i)
        o[1<<i]=i;
    while(~scanf("%d",&n))
    {
        memset(d,0,sizeof(d));
        sum=0;
        for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=n;++j)
            {
                scanf("%d",&a[i][j]);
                d[i]+=a[i][j];//d[i]记录i和其他所有的思念值
                if(i<j) sum+=a[i][j];//记录所有的相互思念值
            }
        }
        solve();//计算所有情况
    }
    return 0;
}

你可能感兴趣的:(hdu 检测赛 Problem C(状压dp))