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

 

posted @ 2022-10-04 12:54  次林梦叶  阅读(40)  评论(0)    收藏  举报