[动态规划] hdu 3602-2012 和 USACO Section 3.4 Rockers

来源:互联网 发布:字中字软件 编辑:程序博客网 时间:2024/04/28 11:50

     周五我们做的杭电OJ上virtual contest,其中有一道《2012》,在problem中的题号为3602。比赛的时候我dp了一下,结果wrong了。发现这个题的题意和我之前做的USACO上Section 3.4 - Rockers 很像,Rockers的题意是从N首歌曲中选出最多数量的歌曲放到M张光盘上,每个光盘只能放T分钟的歌曲,每首歌曲只能在一张盘上,还有个要求就是选出的歌曲放到盘上的顺序必须和原歌曲的顺序相同。由于数据范围很小,规划思想是:用dp[i][j][k]表示前i首歌曲用j张盘,且最后一张盘用了k分钟,代码如下:

/*ID: morgan_xwwLANG: CTASK: rockers*/#include <stdio.h>int Max(int a, int b){    return (a > b ? a : b);}int main(){    freopen("rockers.in", "r", stdin);    freopen("rockers.out", "w", stdout);    int N, M, T, i, j, k;    int a[21];    int dp[21][21][21]={0};    scanf("%d %d %d", &N, &T, &M);    for (i=1; i<=N; i++)        scanf("%d", &a[i]);    for (i=1; i<=N; i++)    for (j=1; j<=M; j++)    for (k=1; k<=T; k++)    {        //不放第i首歌曲;不用第j个盘        dp[i][j][k] = Max(dp[i-1][j][k], dp[i][j-1][T]);        if (a[i] < k)            //把歌曲i插到第j个盘后面            dp[i][j][k] = Max(dp[i][j][k], dp[i-1][j][k-a[i]]+1);        else if (a[i] == k)            //把歌曲i插到一张新盘上            dp[i][j][k] = Max(dp[i][j][k], dp[i-1][j-1][T]+1);    }    printf("%d\n", dp[N][M][T]);    exit(0);}


杭电的这个题意是:N个国家,M个飞船,每个国家有人数num,如果上飞船就给联合国value钱,选出某些国家上船,使联合国赚得的钱最多,而且被选出的国家上船的顺序必须和原给的国家顺序一致。代码如下:
/**    dp[i][j].nship 和 dp[i][j].left 分别表示    从前i个总统赚到j元钱所需要的ship数量和最后一个ship的剩余空间。    dp[i][j]的状态从dp[i-1][j] 和的 dp[i-1][j-v[i]] 转化而来。**/#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;int n, m, k;int maxVal;struct CTY{    int num;    int value;} cty[101];struct DP{    int  nship; //所需的飞船数量    int  left;  //最后一个飞船的剩余空间    bool tag;   //标记该状态是否有效    void setValue(int a, int b, bool c)    {        nship = a;        left = b;        tag = c;    }    void add(DP d, CTY c)    {        if (d.tag == false)            return ;        if (d.left >= c.num)            d.left -= c.num;        else if (c.num <= k)        {            d.nship++;            d.left = k-c.num;        }        else return ;        if (d.nship > m)            return ;        if ( !tag || nship > d.nship || (nship == d.nship && left < d.left) )            setValue(d.nship, d.left, d.tag);    }} dp[101][10001];void solve(){    memset(dp, 0, sizeof(dp));    for (int i=0; i<=n; i++)    {        dp[i][0].setValue(0, 0, true);    }    for (int i=1; i<=n; i++)    {        for (int j=1; j<=maxVal; j++)        {            if (dp[i-1][j].tag)                dp[i][j] = dp[i-1][j];            if (j-cty[i].value >=0)                dp[i][j].add(dp[i-1][j-cty[i].value], cty[i]);        }    }    for (int j=maxVal; j>=0; j--)    {        if (dp[n][j].tag)        {            printf("%d\n", j);            return ;        }    }}int main(){    int  nc;    scanf("%d", &nc);    while (nc--)    {        maxVal = 0;        scanf("%d %d %d", &n, &m, &k);        for (int i=1; i<=n; i++)        {            scanf("%d %d", &cty[i].num, &cty[i].value);            cty[i].num++;            maxVal += cty[i].value;        }        solve();    }    return 0;}