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;
}

  

 

posted @ 2015-05-15 18:44  我不吃饼干呀  阅读(416)  评论(0编辑  收藏  举报