uva 624 CD(01背包问题)输出最小字典序是个问题虽然题目不要求

此题就是赤裸的01背包问题,不过路径是个问题,一开始用逆推得到的程序最后一组数据与题目不符合,我尝试交了一发竟然A了,不过发觉最后一组是按字典序,逆推得到的即不是反字典序也不是字典序。。只不过是其中一组解,此题用的是special judge所以都可以过,我决定想办法得到字典序最小的路径。

最后当然解决了,用vector去保存每一个到达这个背包体积的字典序最小路径,如果遇到当前物品放入的价值跟不放入的价值是一样的,就需要对比2个路径了,从2个vector的头开始对比,如果前者的大于后者,那么就不更新,不放入的字典序最小,反之就更新。

放2个测试数据:

9 4 1 3 4 5
9 4 1 4 3 5

2个答案都是1 3 5 sum:9

这里放2个AC代码,前者是普通的逆推,后者则是字典序输出的路径,速度肯定是前者快。

code 1:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define NMAX 100005
#define ll long long
int a[25],dp[25][2000];
stackans;
void find_path(int x,int y)
{
    if(x==0) return;
    if(dp[x][y] == dp[x-1][y])
        find_path(x-1,y);
    else
    {
        ans.push(x);
        find_path(x-1,y-a[x]);
    }
}

int main()
{
//    freopen("input.txt","r",stdin);
//    freopen("o1.txt","w",stdout);
    int i,j,n,t;
    while(~scanf("%d%d",&n,&t))
    {
        for(i = 1;i <= t; i++) scanf("%d",&a[i]);
        memset(dp,0,sizeof(dp));
        for(i = 1;i <= t; i++)
            for(j = 0; j <= n; j++)
                if(a[i] <= j)
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-a[i]]+a[i]);
                else dp[i][j] = dp[i-1][j];
        find_path(t,n);
        while(!ans.empty())
        {
            printf("%d ",a[ans.top()]);
            ans.pop();
        }
        printf("sum:%d\n",dp[t][n]);
    }
    return 0;
}


code 2:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define NMAX 100005
#define pb push_back
#define ll long long
int a[25],dp[2000];
vector v[2000];

int main()
{
//    freopen("input.txt","r",stdin);
//    freopen("o1.txt","w",stdout);
    int i,j,n,t,sz;
    while(~scanf("%d%d",&n,&t))
    {
        for(i = 1;i <= t; i++)
            scanf("%d",&a[i]);
        for(i = 0; i < n; i++)
            v[i].clear();
        memset(dp,0,sizeof(dp));
        for(i = 1;i <= t; i++)
            for(j = n; j >= 0; j--)
                if(a[i] <= j && dp[j] <= dp[j-a[i]]+a[i])
                {
                    bool flag = 0;
                    v[n+1] = v[j-a[i]];
                    v[n+1].pb(i);
                    if(dp[j] == dp[j-a[i]]+a[i])
                    {
                        sz = v[j].size();
                        for(int k = 0; k < sz; k++)
                            if(v[j][k] > v[n+1][k])
                            {
                                flag = 1;
                                break;
                            }
                        if(flag)
                            v[j] = v[n+1];
                    }
                    else v[j] = v[n+1];
                    dp[j] = dp[j-a[i]]+a[i];
                }
        sz = v[n].size();
        for(i = 0; i < sz; i++)
            printf("%d ",a[v[n][i]]);
        printf("sum:%d\n",dp[n]);
    }
    return 0;
}


你可能感兴趣的:(DP)