light oj 1011 - Marriage Ceremonies

题目大意:

给出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[20][100005],Map[MAXSIZE][MAXSIZE];

int Solve(int n)
{
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<(1<<n);j++)
        {
            int cnt=0;
            for(int k=0;k<n;k++)//优化时间
            {
                if(j&(1<<k)) cnt++;
            }
            if(cnt!=i)
                continue;
            for(int k=0;k<n;k++)
                if(j&(1<<k))
                    dp[i][j]=max(dp[i][j],dp[i-1][j^(1<<k)]+Map[i][k+1]);
        }
    }
    return dp[n][(1<<n)-1];
}

int main()
{
    int T,cns=1,n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        scanf("%d",&Map[i][j]);
        int ans=Solve(n);
        printf("Case %d: %d\n",cns++,ans);
    }
    return 0;
}
View Code

 

posted @ 2017-03-30 17:08  声声醉如兰  阅读(177)  评论(0)    收藏  举报