hdu2546(01ナップザック問題)

Fanka

 

問題の説明

UESTC本社の社員食堂の食事カードは購入前にバランスを決定する非常に奇妙なデザインをしています。製品を購入する前にカードの残量がより多いまたは$ 5と等しい場合、成功を購入することができるようになります(でも、カードの残高を購入した後、負である)、または(量が十分であっても)を購入することはできません。すべてのカードの最低残高を維持するために試してみたい、私たちはそう。
ある日、あるnは食堂は野菜が毎回購入することができ、野菜を販売しました。既知の野菜は、すべての価格とカードの残高は、少なくとも尋ねることができますどのくらいのカードの残高。

 

 

入力

複数のデータセット。各データセットについて:
第一行動の正の整数nは、食器の数を表します。N <= 1000。
2行目のn野菜当たりの価格を表す正の整数を含みます。価格は50以上。
第3段目は、カードの残高を表す、正の整数mを含みます。M <= 1000。

N = 0はデータの終わりを示します。

 

 

出力

整数を含む各入出力ラインの場合は、カード上の可能な最小のバランスを表します。

 

 

サンプル入力

1

50

5

10

1 2 3 2 1 1 2 3 2 1

50

0

 

 

サンプル出力

-45

32

 

最も高価な料理を購入するために5ドルを取得し、残りは、M-5のナップザック問題のバックパックの容量に変換することができます。

なぜ最も高価なを購入する5ドル程度取得は、最適なソリューションです。

そして最後に、皿が最も高価ではありません買いました

全体のプロセスは、最も高価なを購入していない場合は1、最も高価な皿に最後には、より良い結果を得ることができます。

2は、最も高価なを購入する過程、最も高価と最後のスワップは、同じ結果を得ることができます。

質問:最後に、食品の料理は他の最も高価な購入すると購入するために最も高価な時間を購入していないが、同じではありませんが、異なる組み合わせは、より良い結果を生むことがあります。

1は、食べ物を買うために二回、のような、あなたは上記の説明を参照することができます。

二回食べ物を買うために、より良い一致があり、二つが結合していること、同じではありません2、仮定が成り立ちません。

 

故状态方程为sum[i][j]=max(sum[i-1][j],sum[i-1][j-p[i]]+p[i]); sum[i][j]为对第i个物品做出选择后在金额为j的情况下的最大花销。p[i]为第i个物品的价格。即在对第i个物品做出选择(买或不买)时达到的最大花销为max(不买第i个物品时所有金额买其他的物品能达到的最大花销,买第i个物品时剩余金额买其他物品能达到的最大花销+p[i])。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int main(void)
{
    int n;
    int p[1001];
    int m;
    while(cin>>n&&n)
    {
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++)
            cin>>p[i];
        sort(p+1,p+n+1);
        cin>>m;
    if(m>=5)
    {
        int k=1001;
            vector<vector<int> > sum(k);
            for(int i=0;i<k;i++)
                sum[i].resize(k);
        for(int j=0;j<=m-5;j++)//对第一个物品进行选择
        {
            if(j>=p[1])
            {
                sum[1][j]=p[1];//够买则为p[1]
            }
            else sum[1][j]=0;//不够买为0
        }
        for(int i=2;i<n;i++)
            for(int j=0;j<=m-5;j++)
        {
            if(j<p[i])
                sum[i][j]=sum[i-1][j];
            else  sum[i][j]=max(sum[i-1][j],sum[i-1][j-p[i]]+p[i]);
        }
        int result=0;
        for(int i=1;i<n;i++)
            for(int j=0;j<=m-5;j++)
            {
                if(sum[i][j]>result)
                    result=sum[i][j];
            }
            m=m-result-p[n];
        cout<<m<<endl;
    }
    else cout<<m<<endl;
    }
    return 0;
}

遇到的问题,定义二维数组时int sum[1001][1001]时出错,但是数组较小时则不会,此处存疑。故改为用vector。

 

空间优化

状态方程:sum[j]=max(sum[j],sum[j-p[i]]+p[i]);

即采用更新的方式,等式左边sum[j]为当前外层循坏为i求得的值,右边sum[j]为外层循坏为i-1求得的值。

式中右边sum[j-p[i]]中j-p[i]<j,故内层循环采用逆序,即由大到小,否则式子右边sum[j-p[i]]不是前一个状态保留的值,而是当前状态更新过的值。

#include<iostream>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int main(void)
{
    int n;
    int p[1001];
    int m;
    while(cin>>n&&n)
    {
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;i++)
            cin>>p[i];
        sort(p+1,p+n+1);
        cin>>m;
    if(m>=5)
    {
        int sum[1001];
        for(int j=0;j<=m-5;j++)
        {
            if(j>=p[1])
            {
                sum[j]=p[1];
            }
            else sum[j]=0;
        }
        for(int i=2;i<n;i++)
            for(int j=m-5;j>=0;j--)
        {
            if(j<p[i])
                sum[j]=sum[j];
            else  sum[j]=max(sum[j],sum[j-p[i]]+p[i]);
        }
        int result=0;
        for(int i=1;i<n;i++)
            for(int j=m-5;j>=0;j--)
            {
                if(sum[j]>result)
                    result=sum[j];
            }
            m=m-result-p[n];
        cout<<m<<endl;
    }
    else cout<<m<<endl;
    }
  return 0;
}

 

发布了20 篇原创文章 · 获赞 3 · 访问量 5476

おすすめ

転載: blog.csdn.net/treble_csnd/article/details/81565703