LightOJ 1011 - Marriage Ceremonies(狀態壓縮DP)

題意:輸入n 輸入n行n列 從n行中找出n個數 保證任意兩個都不在同一列 求這些數的和。ios

思路: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;
}
相關文章
相關標籤/搜索