CSP-J2 紀念品

題目描述

在這裏插入圖片描述

題目分析

  • 對於T=2T=2,顯然我們可以設一個DP:f[i]f[i]表示第一天買賣前你有ii元,第二天買賣後最多可以有多少錢。
  • 狀態轉移也是比較顯然的:f[i]=max(i,f[ia[k][1]]+a[k][2])f[i]=max(i,f[i-a[k][1]]+a[k][2])
  • 其中kk表示的是紀念品的編號,a[k][1]a[k][1]a[k][2]a[k][2]分別表示該物品第1天和第2天的價值。
  • 最後的答案輸出f[m]f[m]就可以了,時間複雜度是O(1000n)O(1000n)的。
  • 那如果T>2T>2呢。
  • 也有一個小結論:存在一種最優方案,使得第ii天買入的紀念品在i+1i+1天全部賣出,重新買入。
  • 證明:假設最優方案中,有一個商品,必須在第ii天買,第i+k(k>1)i+k(k>1)天賣出。顯然這種方法不比“在第ii天買,第i+1i+1天賣出,再在第i+1i+1天買,第i+2i+2天賣出............在第i+k1i+k-1天買,最終在第i+ki+k天賣出”更優。
  • 依據這個結論,我們可以把剛纔的T=2T=2的方法循環重複做T1T-1次,時間複雜度O(1000Tn)O(1000Tn)

代碼

#include<cstdio>
#include<cstring>
using namespace std;
const int N=110,M=1e4+100;
int a[N][N],f[N][M];
int mymax(int x,int y) {return x>y?x:y;}
int main()
{
	freopen("souvenir.in","r",stdin);
	freopen("souvenir.out","w",stdout);
	int t,n,m;
	scanf("%d%d%d",&t,&n,&m);
	for(int i=1;i<=t;i++)
		for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
	memset(f,0,sizeof(f));
	int maxn=10000;
	for(int i=0;i<=maxn;i++) f[1][i]=i;
	for(int i=t;i>=2;i--){
		for(int j=0;j<=maxn;j++) f[i][j]=j;
		for(int j=1;j<=n;j++){
			if(a[i-1][j]>=a[i][j]) continue;
			for(int k=a[i-1][j];k<=maxn;k++){
				int t=f[i][k-a[i-1][j]]+a[i][j];
				f[i][k]=mymax(f[i][k],t);
			}
		}
		for(int j=maxn;j>=0;j--){
			if(f[i][j]<=maxn) {maxn=j;break;}
		}
	}
	for(int i=2;i<=t;i++) m=f[i][m];
	printf("%d\n",m);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章