本题是一道背包上限可以变化的多重部分和问题,此处给出了粗略题解
题目来源:(未知)
题面题目描述
llk经常和wy一起去yh小饭馆吃盖浇饭,一天他们吃完后llk把两个人的钱一起付了,但是wy不想欠llk的钱。
现在wy手中有一些散钱,llk手中也有一些散钱,wy想知道能不能刚好使得两不相欠,但是wy很笨,你能帮助wy吗?
输入
多组测试数据,每组第一行输入3个非负整数,C,n,m。C代表wy欠llk的钱,n代表wy手中钱面值的种类,m代表llk手中钱面值的种类。
接下来的n行,每行两个数v, c,分别代表wy手中面值为v的钱币有c个。再接下来的m行,每行两个数v,c,分别代表llk手中面值为v的钱币有c个。
(C <= 10000; 1<=n, m<50; 0<=v < =100; 0<=c<=10 )
输出
每组数据输出一行,如果存在一种方案使得wy和llk两不相欠,输出YES,否则输出NO。
样例输入
7 1 1
10 1
1 10
样例输出
YES
提示
wy给了llk一张10元的,llk又给了wy三个1元的
参考代码
#include #include #include using namespace std;int main(){ ios::sync_with_stdio(false); int c, n, m; while (cin >> c >> n >> m) { pair *money = new pair[n + m]; // 存放输入的钱和数量 int limit = 0; // 背包容量可扩上限(因为llk会改变背包容量) // 输入钱的面值和数量 for (int i = 0; i > money[i].first >> money[i].second; if (i >= n) { limit += money[i].first * money[i].second; // 调整背包容量上限 } } // 初始状态 vector dp(c + limit + 1, -1); dp[0] = 0; // new一个数组是会re,所以此处用vector // 状态转移wy,状态定义为当前钱放满之后剩多少个,<0为放不了 for (int i = 0; i < n; i++) // 第i种钱 { for (int j = 0; j = 0) // 已经满了 { dp[j] = money[i].second; // 当前全部剩下 } else if (j < money[i].first || dp[j - money[i].first] <= 0) // 放不满 { dp[j] = -1; } else // 前面多出来的一个使之放满,所以剩下的少一个 { dp[j] = dp[j - money[i].first] - 1; } } } // 状态转移llk,状态定义为还能用第i种钱减小几次使得背包能放满,<0为减小了也放不了 for (int i = n; i = c; j--) // 用llk的钱来扩大背包总容量,需要当次后面的数据,所以要倒着 { if (dp[j] >= 0) // 已经满了 { dp[j] = money[i].second; // 当前全部剩下 } else if (j + money[i].first > c + limit || dp[j + money[i].first] <= 0) // 扩大不了 { dp[j] = -1; } else // 用前面多出来的一个扩大背包总容量,所以剩下的少一个 { dp[j] = dp[j + money[i].first] - 1; } } } cout <= 0 ? "YES" : "NO") << "\n"; // 检查下dp[c]的状态对不对即可 } return 0;}
“正是我们每天反复做的事情,最终造就了我们,优秀不是一种行为,而是一种习惯” —亚里士多德
这里是浙江理工大学22届ACM集训队的成员一枚鸭!
本文首发于博客园,作者:星双子,除了我自己的转载请注明原文链接:https://www.cnblogs.com/geministar/p/repayment_of_debts.html