dp----得到方案方法的技巧
《题一》
原题链接:https://atcoder.jp/contests/abc271/tasks/abc271_d
翻译:
问题陈述
有N张卡片,每面写一个整数。卡片 正面写着一个整数ai,背面写着一位整数bi。
您可以选择将每张卡片的正面或背面都显示出来。
确定您是否可以放置卡片,使可见整数的总和正好等于S。如果可能,请找到卡片的位置以实现它。
如果只是问是否可以组成出来,十分好做,但是还要求方案
解决之道:
首先利用dp[i][j]:在前i张卡片中选择,能够到达数值正好为j,如果能为1,如果不能为0
然后利用反推
其实就是如果dp[i][j]==1,那么这个必然是通过dp[i-1][j-a[i].first]或dp[i-1][j-a[i].second]转移过来
必然dp[i-1][j-a[i].first]或dp[i-1][j-a[i].second]有一个为1,如果两个都为1选择其中一个即可
1 #include <iostream>
2 #include <cstring>
3 #include <algorithm>
4 using namespace std;
5 typedef pair<int, int> PII;
6 const int N = 101, S = 10001;
7 int n, s, dp[N][S];
8 PII a[N];
9 int main()
10 {
11 cin >> n >> s;
12 for (int i = 1; i <= n; i++)
13 {
14 int z, f;
15 scanf("%d%d", &z, &f);
16 a[i] = {z, f};
17 }
18 dp[0][0] = 1;
19 for (int i = 1; i <= n; i++)
20 for (int j = 1; j <= s; j++)
21 {
22 if (j >= a[i].first)
23 dp[i][j] |= dp[i - 1][j - a[i].first];
24 if (j >= a[i].second)
25 dp[i][j] |= dp[i - 1][j - a[i].second];
26 }
27 if (dp[n][s])
28 {
29 cout << "Yes" << endl;
30 string str = "";
31 for (int i = n; i >= 1; i--)
32 {
33 if (s >= a[i].first && dp[i - 1][s - a[i].first])
34 {
35 str += 'H';
36 s -= a[i].first;
37 }
38 else if (s >= a[i].second && dp[i - 1][s - a[i].second])
39 {
40 str += 'T';
41 s -= a[i].second;
42 }
43 }
44 for (int i = str.size() - 1; i >= 0; i--)
45 cout << str[i];
46 }
47 else
48 cout << "No";
49 return 0;
50 }
详细题解:https://atcoder.jp/contests/abc271/editorial/4939