hdu 01背包汇总(1171+2546+1864+2955。。。
1171
题意比较简单,这道题比较特别的地方是01背包中,每个物体有一个价值有一个重量,比较价值最大,重量受限,这道题是价值受限情况下最大,也就值把01背包中的重量也改成价值。
//Problem : 1171 ( Big Event in HDU ) Judge Status : Accepted #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; int v[6000], dp[5000 * 50 + 10]; int main() { //freopen("in.txt", "r", stdin); int n; int sum; while (scanf("%d", &n) != EOF && n >= 0) { memset(dp, 0, sizeof(dp)); int a, b; sum = 0; int idx = 0; for (int i = 1; i <= n; i++) { scanf("%d%d", &a, &b); sum += a * b; for (int j = 0; j < b; j++) { v[++idx] = a; } } for (int i = 1; i <= idx; i++) for (int j = sum / 2; j >= v[i]; j--) dp[j] = max(dp[j], dp[j - v[i]] + v[i]); printf("%d %d\n", sum - dp[sum / 2], dp[sum / 2]); } return 0; }
2546
和上面一样,没有重量,只有价值。
如果卡上不足5元,输出原值。如果大于5元,就在m-5范围内花最多的钱(留下最贵的菜),然后用剩下的钱减去最贵的菜。
代码
//Problem : 2546 ( 饭卡 ) Judge Status : Accepted #include <iostream> #include <algorithm> using namespace std; int v[1005]; int dp[1005]; int main() { int n, m; while (cin >> n && n) { memset(dp, 0, sizeof(dp)); //又忘记初始化然后wa了一发。。。 for (int i = 1; i <= n; ++i) { cin >> v[i]; } cin >> m; if (m < 5) { printf("%d\n", m); continue; } sort(v + 1, v + n + 1); for (int i = 1; i < n; ++i) { for (int j = m - 5; j >= v[i]; j--) dp[j] = max(dp[j], dp[j - v[i]] + v[i]); } printf("%d\n", m - dp[m - 5] - v[n]); } return 0; }
2602
水题,不写了。基本01背包。
1864
题意很简单,做法也很简单,全部*100变成整数然后01背包。
一处(int)(q*100)不小心写成了(int)q*100调试了好久才找到,蠢蠢蠢= =
//Problem : 1864 ( 最大报销额 ) Judge Status : Accepted /**< hdu 1864 */ #include <iostream> #include <cstdio> #include <algorithm> using namespace std; double pri[35]; //合法发票的价格 int pric[35]; int dp[35 * 1000 * 100]; int main() { double q; int n, m; double pri_a, pri_b, pri_c; while (scanf("%lf%d", &q, &n) != EOF && n) { int idx = 0; for (int i = 0; i < n; ++i) { cin >> m; pri_a = pri_b = pri_c = 0; char ch; double price; int ok = 1; for (int j = 0; j < m; ++j) { scanf(" %c:%lf", &ch, &price); switch(ch) { case 'A' : pri_a += price; break; case 'B' : pri_b += price; break; case 'C' : pri_c += price; break; default: ok = 0; } } double sum = pri_a + pri_b + pri_c; //printf("a=%f,b=%f,c=%f,sum=%f\n", pri_a, pri_b, pri_c, sum); if (!(pri_a > 600 || pri_b > 600 || pri_c > 600 || sum > 1000) && ok) pri[++idx] = sum; } //end for 求出pri[] for (int i = 1; i <= idx; i++) { pric[i] = (int)(pri[i] * 100); } memset(dp, 0, sizeof(dp)); for (int i = 1; i <= idx; ++i) { for (int j = (int)(q * 100); j >= pric[i]; --j) { dp[j] = max( dp[j], dp[j - pric[i]] + pric[i]); } } printf("%.2f\n", dp[(int)(q * 100)] / 100.00); } return 0; }
这题也可以换一种方法做,用张数当背包。
我们平时的背包都是质量,当数据过大,或像这个一样是实数,可以转换思维,用价值当背包等。
//Problem : 1864 ( 最大报销额 ) Judge Status : Accepted #include <iostream> #include <cstdio> #include <algorithm> using namespace std; double pri[35]; double dp[35]; int main() { double q; int n, m; double pri_a, pri_b, pri_c; while (scanf("%lf%d", &q, &n) != EOF && n) { int idx = 0; for (int i = 0; i < n; ++i) { cin >> m; pri_a = pri_b = pri_c = 0; char ch; double price; int ok = 1; for (int j = 0; j < m; ++j) { scanf(" %c:%lf", &ch, &price); switch(ch) { case 'A' : pri_a += price; break; case 'B' : pri_b += price; break; case 'C' : pri_c += price; break; default: ok = 0; } } double sum = pri_a + pri_b + pri_c; //printf("a=%f,b=%f,c=%f,sum=%f\n", pri_a, pri_b, pri_c, sum); if (!(pri_a > 600 || pri_b > 600 || pri_c > 600 || sum > 1000) && ok) pri[++idx] = sum; } //end for 求出pri[] for (int i = 0; i <= idx; i++) { dp[i] = 0.0; } for (int i = 1; i <= idx; ++i) { for (int j = idx; j >= 1; --j) { if (dp[j - 1] + pri[i] <= q) dp[j] = max(dp[j], dp[j - 1] + pri[i]); } } double ans = 0; for (int i = 1; i <= idx; ++i) if (ans < dp[i]) ans = dp[i]; printf("%.2f\n", ans); } return 0; }
2955
又是一道不是整数的题,可以看出这道题不能像上一道那样简答的通过x100完成,因为精度不够。
可以把概率当背包,这题还有一处不同就是不是加,概率是乘
//Problem : 2955 ( Robberies ) Judge Status : Accepted #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; double P[105]; //每一家银行不被抓的概率 int M[105]; //每一家银行偷到的钱... double dp[10005]; int main() { int t; cin >> t; while (t--) { int n; int sum = 0; double p; cin >> p >> n; for (int i = 1; i <= n; ++i) { cin >> M[i] >> P[i]; P[i] = 1 - P[i]; sum += M[i]; } memset(dp, 0, sizeof(dp));//又特么忘了这句wa一发。。。 dp[0] = 1; //不偷时不被抓概率是1 for (int i = 1; i <= n; ++i) { for (int j = sum; j >= M[i]; --j) { dp[j] = max(dp[j], dp[j - M[i]] * P[i]); //不被抓的概率最大 } } for (int i = sum; i >= 0; --i) if (dp[i] > 1 - p) { printf("%d\n", i); break; } } return 0; }