ZOJ 3777 Problem Arrangement(状压DP)

题目链接 : http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5264

//今年省赛的题目,比赛的时候知道是状压却一直没搞出,直到最后。虽然赛后知道做法,也一直没做的,最近想不开就来做了 - -, 顺便用了下快速枚举k-子集。

恩, 做法么就是开dp[i][j] i已经选过了的题目的一个集合,j表示的是获得了j分,然后就可以直接做了。。(但是好像说会T或者卡空间,我的做法是快速枚举k-子集,这个东西可以看下watashi翻译的《挑战编程竞赛》的p157。。 汗

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 //#include <cmath>
 6 
 7 using namespace std;
 8 
 9 int P[15][15];
10 int dp[1<<12][505];
11 int n, m;
12 
13 int main() {
14     int T;
15     scanf("%d", &T);
16     for (int cas = 1; cas <= T; cas++) {
17         scanf("%d%d", &n, &m);
18         for (int i = 1; i <= n; i++) {
19             for (int j = 1; j <= n; j++) scanf("%d", &P[i][j]);
20         }
21         memset(dp, 0, sizeof(dp)); dp[0][0] = 1;
22 
23         for (int k = 1; k <= n; k++) {
24             int comb = (1 << k) - 1;
25             while (comb < (1 << n)) {
26                 for (int i = 0; i < n; i++) {
27                     if (comb >> i & 1) {
28                         int add = P[i + 1][k], low = max(0, m-add);
29                         for (int j = m; j >= low; j--) dp[comb][m] += dp[comb-(1<<i)][j];
30                         for (int j = low - 1; j >= 0; j--) dp[comb][j+add] += dp[comb-(1<<i)][j];
31                     }
32                 }
33                 if (comb == 0) break;
34                 int x = comb & -comb, y = comb + x;
35                 comb = ((comb & ~y) / x >> 1) | y;
36             }
37         }
38         int ret = dp[(1<<n)-1][m];
39         if (!ret) puts("No solution");
40         else {
41             int nex = 1;
42             for (int i = 1; i <= n; i++) nex *= i;
43             int d = __gcd(ret, nex);
44             printf("%d/%d
", nex/d, ret/d);
45         }
46     }
47     return 0;
48 }
View Code
原文地址:https://www.cnblogs.com/danceonly/p/4004410.html