UESTC 1218 Pick The Sticks
阿新 • • 發佈:2019-02-17
題意:給出一個長度為L的棍狀容器 和n個長度為li價值為vi的棍狀物品 物品只能直接放在容器上 且只要重心在容器上即可(包含邊界)求能放置的物品的最大的總價值
題解:很容易看出是動態規劃的題目,而此題有一個重要的結論,你所選的物品中,可以將長度最長的兩個置於兩邊,這樣外延的長度儘量長,肯定是最優的,所以我們先按長度對物品從小到大排序,dp[i][j]表示到第i個木棍總長度為j時能獲得的最大價值,這裡dp先按常規的揹包跑一遍,最後在掃一遍處理下即可。
之後n²的列舉在兩端的邊是哪兩個,中間的值即2端次短的物品對於的dp值。(這裡注意奇數時的邊界處理 長度為6的容器上可以放一個長度為1的加兩個長度為5的物品)
最後特殊考慮下有一個木棍長於總容器的情況即可(即樣例4中的情況)。
注意會超int
#include<iostream> #include<cstdio> #include<cstring> #include<cctype> #include<cmath> #include<vector> #include<queue> #include<map> #include<algorithm> #include<set> #define scnaf scanf #define cahr char #define bug puts("========================="); using namespace std; typedef long long ll; const int mod=1000000007; const int maxn=1000+50; struct T{ int l,v; bool operator < (const T &b) const{ return l<b.l; } }a[maxn]; ll dp[maxn][2*maxn]; int main() { int T_T,test=1; scanf("%d",&T_T); while(T_T--) { int n,m; scanf("%d%d",&n,&m); for(int i=0;i<n;i++){ scanf("%d%d",&a[i].l,&a[i].v); } sort(a,a+n); memset(dp,0,sizeof(dp)); for(int i=0;i<n;i++){ for(int j=0;j<=m;j++) dp[i+1][j]=dp[i][j]; for(int j=0;j+a[i].l<=m;j++) dp[i+1][j+a[i].l]=max(dp[i+1][j+a[i].l],dp[i][j]+a[i].v); } for(int i=0;i<=n;i++) for(int j=1;j<=m;j++) dp[i][j]=max(dp[i][j],dp[i][j-1]); ll ans=a[n-1].v; ans=max(ans,dp[n][m]); for(int i=n-1;i>=0;i--) { int len=m-(a[i].l+1)/2; if(len<0) continue; ans=max(ans,dp[i][len]+a[i].v); for(int j=i-1;j>=0;j--){ len=m-(a[i].l+a[j].l+1)/2; if(len<0) continue; ans=max(ans,dp[j][len]+a[i].v+a[j].v); } } printf("Case #%d: %lld\n",test++,ans); } return 0; }