状压DP汇总

P1441 砝码称重

题目描述

现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0)。

输入输出格式

输入格式:

输入文件weight.in的第1行为有两个整数n和m,用空格分隔

第2行有n个正整数a1,a2,a3,……,an,表示每个砝码的重量。

输出格式:

输出文件weight.out仅包括1个整数,为最多能称量出的重量。

输入输出样例

输入样例#1: 
3 1
1 2 2
输出样例#1: 
3

说明

【样例说明】

在去掉一个重量为2的砝码后,能称量出1,2,3共3种重量。

【数据规模】

对于20%的数据,m=0;

对于50%的数据,m≤1;

对于50%的数据,n≤10;

对于100%的数据,n≤20,m≤4,m<n,ai≤100。

code

 1 #include<bitset>
 2 #include<cstdio>
 3 #include<iostream>
 4 #define f(i,x,n) for(int i=x;i<=n;++i)
 5 using namespace std;
 6 
 7 int n, m, a[21];
 8 int ans;
 9 
10 int bit(int x) {
11     int cnt = 0;
12     f(i, 0, n - 1) if (x & (1 << i)) cnt++;
13     return cnt;
14 }
15 
16 int main() {
17     cin >> n >> m;
18     f(i, 0, n - 1) cin >> a[i];
19     f(i, 0, (1<<n)-1) if (bit(i) == n - m) {
20         bitset<2010> t;
21         t[0] = 1;
22         f(j, 0, n - 1) if (i & (1<<j)) {
23             t = t | t << a[j];
24             ans = max(ans, (int)t.count());
25         }
26     } 
27     cout << ans - 1 << endl;
28     return 0;
29 }

P2622 关灯问题II

题目描述

现有n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果。按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是0,无论这灯是否开,都不管。

现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。

输入输出格式

输入格式:

前两行两个数,n m

接下来m行,每行n个数,a[i][j]表示第i个开关对第j个灯的效果。

输出格式:

一个整数,表示最少按按钮次数。如果没有任何办法使其全部关闭,输出-1

输入输出样例

输入样例#1: 
3
2
1 0 1
-1 1 0
输出样例#1: 
2

说明

对于20%数据,输出无解可以得分。

对于20%数据,n<=5

对于20%数据,m<=20

上面的数据点可能会重叠。

对于100%数据 n<=10,m<=100

code

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <iostream>
 5 #include <algorithm>
 6 #include <map>
 7 using namespace std;
 8 
 9 const int INF = 0x3f3f3f3f;
10 int n, m, a[110][1100];
11 int f[1100];
12 
13 int main() {
14     cin >> n >> m;
15     for (int i = 1; i <= m; ++ i)
16         for (int j = 1; j <= n; ++ j)
17             cin >> a[i][j];
18     for (int i = 0; i < (1<<n); ++ i) f[i] = INF;
19     f[0] = 0;
20     for (int i = 0; i < (1<<n); ++ i)
21         for (int j = 1; j <= m; ++ j) {
22             int t = i;
23             for (int k = 0; k < n; ++ k)
24                 if (((a[j][k+1]==1)&&!(i&1<<k)) || (a[j][k+1]==-1)&&(i&1<<k))
25                     t ^= 1 << k;
26             f[t] = min(f[t], f[i] + 1); 
27         }
28     if (f[(1<<n)-1] == INF) cout << "-1" << endl;
29     else cout << f[(1<<n)-1] << endl;
30     return 0;
31 }

P1896 [SCOI2005]互不侵犯

题目描述

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。

注:数据有加强(2018/4/25)

输入输出格式

输入格式:

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出格式:

所得的方案数

输入输出样例

输入样例#1: 
3 2
输出样例#1: 

16

code

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <iostream>
 5 #include <algorithm>
 6 #define f(i, x, n) for(int i=x;i<=n;++i)
 7 using namespace std;
 8 
 9 typedef long long LL;
10 const int MAXX = 110;
11 int N, K;
12 int tot, s0, s[MAXX], num[MAXX];
13 LL ans, dp[10][MAXX][MAXX];
14 
15 int main() {
16     cin >> N >> K;
17     f(i, 0, (1<<N)-1) { //枚举每行状态
18         if (i & (i<<1)) continue; //判断是否冲突
19         tot = 0;
20         f(j, 0, N-1) 
21             if (i & (1<<j)) tot++; //统计放置数量
22         s[++s0] = i; //标记可行方案
23         num[s0] = tot; 
24     }
25     dp[0][1][0] = 1;
26     f(i, 1, N) f(j, 1, s0) f(k, 0, K) 
27         if (k >= num[j]) f(t, 1, s0) 
28             if (!(s[t]&s[j])&&!(s[t]&(s[j]<<1))&&!(s[t]&s[j]>>1))
29                 dp[i][j][k] += dp[i - 1][t][k - num[j]];
30     f(i, 1, s0) ans += dp[N][i][K];
31     cout << ans << endl;
32     return 0;
33 }

P2704 [NOI2001]炮兵阵地

题目描述

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

输入输出格式

输入格式:

第一行包含两个由空格分割开的正整数,分别表示N和M;

接下来的N行,每一行含有连续的M个字符(‘P’或者‘H’),中间没有空格。按顺序表示地图中每一行的数据。N≤100;M≤10。

输出格式:

仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

输入输出样例

输入样例#1: 
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
输出样例#1: 

6

code

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<iostream>
 5 #include<algorithm>
 6 #define f(i, x, n) for(int i=x;i<n;++i)
 7 using namespace std;
 8 
 9 const int MAXN = 100;
10 const int MAXM = 10;
11 int N, M, ans;
12 int t[MAXN], sum[(1<<10)], dp[(1<<10)][(1<<10)][3];
13 
14 void init() {
15     cin >> N >> M;
16     f(i, 0, N) f(j, 0, M) {
17         char x; cin >> x;
18         t[i] <<= 1, t[i] += (x == 'H' ? 1 : 0);
19     }
20 }
21 
22 int getsum(int i) {
23     int tot = 0;
24     while(i) { if (i & 1) ++ tot; i >>= 1; }
25     return tot;
26 }
27 
28 bool pd(int s) { return ((s & (s << 1)) || (s & (s << 2))); }
29 
30 int main() {
31     init();
32     f(i, 0, (1 << M)) sum[i] = getsum(i);
33     f(l, 0, (1 << M)) f(s, 0, (1 << M))
34         if (!(l & s || l & t[0] || s & t[1] || pd(l) || pd(s)))
35             dp[l][s][1] = sum[s] + sum[l];
36     f(i, 2, N) f(l, 0, (1 << M)) {
37         if (l & t[i - 1] || pd(l)) continue;
38         f(s, 0, (1 << M)) {
39             if (s & t[i] || l & s || pd(s)) continue;
40             f(p, 0, (1 << M)) {
41                 if (p & l || p & s || p & t[i - 2] || pd(p)) continue;
42                 dp[l][s][i % 3] = max(dp[l][s][i % 3], 
43                     dp[p][l][(i - 1) % 3] + sum[s]);
44             }
45         }
46     }
47     f(l, 0, (1 << M)) f(s, 0, (1 << M)) 
48         ans = max(ans, dp[l][s][(N - 1) % 3]);
49     cout << ans << endl;
50     return 0;
51 }

猜你喜欢

转载自www.cnblogs.com/hkttg/p/9374367.html