这虽然是一道水题,然而我Debug了快一个点儿,于是决定在A了之后发篇博客。
这显然是一个有依赖性的背包问题,但是因为这道题一个主件最多只有两个附件,所以只有4种情况:
1.只选主件
2.主件+附件1
3.主件+附件2
4.主件+附件1+附件2
(5.都不选)
而且这四种情况是互斥的,那么这就相当于分组背包中的一个组,把原始的物品拆成上述新的物品(组合)后,跑正常的分组背包就行。
题解里面开了个vector记录了每一个组(代码巨丑)。
![[NOIP2006]金明的预算方案_编程开发](https://s2.51cto.com/images/blog/202105/28/334f91f2bcda739f616d7675236c4535.gif?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
![[NOIP2006]金明的预算方案_C 教程_02](https://s2.51cto.com/images/blog/202105/28/bba444e725227017d14bda03c9acd6a8.gif?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=)
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cctype> 7 #include<cstdlib> 8 #include<queue> 9 #include<stack> 10 #include<vector> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 #define pr pair<int, int> 17 #define mp make_pair 18 typedef long long ll; 19 typedef double db; 20 const db eps = 1e-8; 21 const int INF = 0x3f3f3f3f; 22 const int maxm = 65; 23 const int maxn = 32005; 24 inline ll read() 25 { 26 ll ans = 0; 27 char ch = getchar(), las = ' '; 28 while(!isdigit(ch)) las = ch, ch = getchar(); 29 while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); 30 if(las == '-') ans = -ans; 31 return ans; 32 } 33 inline void write(ll x) 34 { 35 if(x < 0) putchar('-'), x = -x; 36 if(x >= 10) write(x / 10); 37 putchar(x % 10 + '0'); 38 } 39 40 int m,n; 41 vector<int> item[maxm]; 42 struct Node 43 { 44 int v, p, q; 45 }e[maxm]; 46 47 vector<pr> v[maxm]; 48 int cnt = 0; 49 ll dp[maxm][maxn]; 50 51 int main() 52 { 53 n = read(); m = read(); 54 for(int i = 1; i <= m; ++i) 55 { 56 e[i].v = read(); e[i].p = read(); e[i].q = read(); 57 if(e[i].q) item[e[i].q].push_back(i); 58 } 59 for(int i = 1; i <= m; ++i) 60 { 61 if(item[i].size()) 62 { 63 v[++cnt].push_back(mp(e[i].v, e[i].v * e[i].p)); 64 v[cnt].push_back(mp(e[i].v + e[item[i][0]].v, e[i].v * e[i].p + e[item[i][0]].v * e[item[i][0]].p)); 65 if(item[i].size() == 2) 66 { 67 v[cnt].push_back(mp(e[i].v + e[item[i][1]].v, e[i].v * e[i].p + e[item[i][1]].v * e[item[i][1]].p)); 68 v[cnt].push_back(mp(e[i].v + e[item[i][0]].v + e[item[i][1]].v, e[i].v * e[i].p + e[item[i][0]].v * e[item[i][0]].p + e[item[i][1]].v * e[item[i][1]].p)); 69 } 70 } 71 else if(!e[i].q) v[++cnt].push_back(mp(e[i].v, e[i].v * e[i].p)); 72 } 73 for(int k = 1; k <= cnt; ++k) 74 for(int i = 0; i < (int)v[k].size(); ++i) 75 for(int j = n; j >= 0; --j) 76 { 77 dp[k][j] = max(dp[k][j], dp[k - 1][j]); 78 if(j - v[k][i].first >= 0) dp[k][j] = max(dp[k][j], dp[k - 1][j - v[k][i].first] + v[k][i].second); 79 write(dp[cnt][n]), enter; 80 return 0; 81 }
题解到此结束,下面是我debug过程:
1.快速的写完且过了样例后,交上去只有20,然后发现写成了01背包。
2.开始改成分组背包,因为组数的序号问题出现了空的组,debug了10多分钟。
3.最后改完后还是gg,下载的样例过不去,陷入无穷的debug过程。
4.终于发现竟然是分组背包写错了,原来01背包偷懒的写法for(int j = m; i >= c[i]; --j)在分组背包里是错的,这样会导致一些好的状态没有继承,所以还是乖乖从m枚举到0吧……