题意:给一个N*N的二维数组,从中选出N个数 要求不能同行同列, 求这N个数最大数的和 状态压缩。
每个i+1由上一个i推出来,这个直接一个for 搞一下就可以,剩下的就是枚举每个列。开一个dp[1<<16],二进制1表示我不在这一列中选取,0表示在这一列选取了数字。
(1<<n)-1表示初始化 全部都置1,然后从最后一行往前推就可以了。
异或表示去掉一个1,比如1000&1010 = 1000 然后1010^1000 = 0010,这样就去掉了一个1 ,就表示我要选择这列
m-1 就表示换到下一层。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#pragma warning (disable :4996)
using namespace std;
const int Max = 1 << 16;
int dp[Max],a[20][20],n;
int dfs(int x, int m)
{
if (m == 0)return 0;
if (dp[x])return dp[x];
for (int i = 0; i < n; i++)
{
if ((1 << i)&x)//判断第x列有没有被选取过
dp[x] = max(dp[x], dfs((1 << i) ^ x, m - 1) + a[m - 1][i]);//如果没被选取,那么要从选这列和不选这列中选值最大的一个,异或符号表示把从里面去掉一个1,就表示选了这列,然后加上对应的权值就可以了
}
return dp[x];
}
int main()
{
int T;
scanf("%d", &T);
for (int t = 1; t <= T;t++)
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
scanf("%d", &a[i][j]);
memset(dp, 0, sizeof(dp));
printf("Case %d: %d\n", t, dfs((1 << n) - 1, n));
}
return 0;
}