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;

}

  

 

你可能感兴趣的:(HDU)