light oj 1011 - Marriage Ceremonies

时间:2022-08-24 16:14:54

题目大意:

给出n*n的矩阵Map,Map[i][j]代表第i个男人和第j个女人之间的满意度,求男女一一配对后,最大的满意度之和。

题目思路:状态压缩

题目可看做每行取一点,所有点不同列的情况下,各个点的最大和为多少。

dp[i][j],代表第i行,状态为j的情况下的最优解,其中j的含义为:j所代表的二进制数中:若第i位为1则取第i列的值,为0则不取。

这样j从1到(1<<n)-1,便包含了矩阵中所有列的取法

为了节约时间,我们需要作出一点优化:我们知道i*i的矩阵中不可能存在比i大的列,也就是说(i&(1<<k)应该大于0,k从0到n-1)。

得出状态转移方程式:dp[i][j]=max(dp[i][j],dp[i-1][j^(1<<k)]+Map[i][k+1])

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#define LL long long
#define MAXSIZE 1005
using namespace std; int dp[][],Map[MAXSIZE][MAXSIZE]; int Solve(int n)
{
memset(dp,,sizeof(dp));
for(int i=;i<=n;i++)
{
for(int j=;j<(<<n);j++)
{
int cnt=;
for(int k=;k<n;k++)//优化时间
{
if(j&(<<k)) cnt++;
}
if(cnt!=i)
continue;
for(int k=;k<n;k++)
if(j&(<<k))
dp[i][j]=max(dp[i][j],dp[i-][j^(<<k)]+Map[i][k+]);
}
}
return dp[n][(<<n)-];
} int main()
{
int T,cns=,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
scanf("%d",&Map[i][j]);
int ans=Solve(n);
printf("Case %d: %d\n",cns++,ans);
}
return ;
}