zoj 3777(狀態壓縮dp)

// 題意:求一個長度爲n的序列 所有的排列組成的疲勞值大於m的數量
// 也就是求一個矩陣每行每列只能取一個得到的所有數字大於m共有多少種
// n最大爲12 m最大爲500 所以採用狀態壓縮
// 學習了別人的思路 dp[i][j] 表示狀態爲i,疲勞值大於等於j的排列有多少種
// 接着就是由dp[i][j]推導出 dp[(1<<n) - 1][m] 即可
#include <algorithm>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
int sum[15];
int dp[1<<13][505];
int calcu()
{
    sum[1] = 1;
    for(int i = 2; i <= 12; i++)
        sum[i] = sum[i - 1] * i;
    return 0;
}
int gcd(int a, int b)
{
    return b == 0? a: gcd(b, a%b);
}
int main()
{
    int t;
    int ss[15][15];
    calcu();
    cin>>t;
    int cnt;
    while(t--)
    {
        int n, m;
        cin>>n>>m;
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
                cin>>ss[i][j];
        memset(dp, 0, sizeof dp);
        dp[0][0] = 1;
        for(int i = 0; i <= (1<<n); i++)
        {
            cnt = 0;
            for(int j = 1; j <= n; j++)
                if(i & (1 << (j - 1)))
                    cnt ++;
            
            for(int j = 1; j <= n; j++)
            {
                if(i & (1<<(j - 1)))
                    continue;
                for(int k = 0; k <= m; k++)
                    if(k + ss[cnt + 1][j] >= m)
                        dp[i + (1<<(j - 1))][m] += dp[i][k];
                    else
                        dp[i + (1<<(j - 1))][k + ss[cnt + 1][j]] += dp[i][k];
            }
        }
        if(dp[(1<<n) - 1][m] == 0)
            cout<<"No solution"<<endl;
        else {
            int fn = gcd(dp[(1<<n) - 1][m], sum[n]);
            cout<<sum[n]/fn<<'/'<<dp[(1<<n) - 1][m]/fn<<endl;
        }
    }
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章