LightOJ 1011 - Marriage Ceremonies(状态压缩DP)

题意:输入n 输入n行n列 从n行中找出n个数 保证任意两个都不在同一列 求这些数的和。

思路:dp[i][j]表示前i个选的列状态为j。需要注意的是一个优化,代码中有标识

#include <iostream>
#include <cstdio>
#include <stack>
#include <cstring>

using namespace std;

int a[20][20];
int dp[20][70000];

int main()
{
    int t, n;
    scanf("%d", &t);
    int tt = 1;
    while(t--)
    {
        scanf("%d", &n);
        for(int i=1; i<=n; i++)
        {
            for(int j=1; j<=n; j++)
            {
                scanf("%d", &a[i][j]);
            }
        }
        int maxn = 1<<n;
        for(int i=0; i<=n; i++)
            for(int j=0; j<=maxn; j++)
                dp[i][j] = 0;
        for(int i=1; i<=n; i++)
        {
            for(int j=0; j<maxn; j++)
            {
                int cnt = 0;
                for(int k=0; k<n; k++)//一步优化 就是当前i-1的状态下有不是i-1个组成的话 pass掉
                    if(j & (1<<k))
                        cnt++;
                if (cnt != i-1)
                    continue;
                for(int k=1; k<=n; k++)
                {
                    int st = 1<<(k-1);
                    if((st&j)==0)
                    {
                        dp[i][st|j] = max(dp[i][st|j], dp[i-1][j]+a[i][k]);
                    }
                }
            }
        }

        printf("Case %d: %d\n", tt++, dp[n][(1<<n)-1]);
    }

    return 0;
}

 

posted @ 2016-08-01 12:04  梦中。。  阅读(220)  评论(0编辑  收藏  举报