洛谷P4138 掛飾 背包
阿新 • • 發佈:2018-11-24
而已 ems getch cli 決定 ora truct har http
正解:背包dp
解題報告:
昂先放鏈接qwq
感覺還挺妙的,,,真的我覺得我直接做可能是想不到背包的,,,我大概想不出是個背包的QAQ
但是知道是背包之後覺得,哦,好像長得也確實挺背包的吼,而且其實是個比較經典的樣子
所以為什麽想不到呢,,,大概就 基礎不牢地動山搖趴QAQ(不其實就是菜而已
然後大概隨便港下就成qwq
首先是很明顯是個01背包咯,然後就思考怎麽設狀態怎麽轉移
直接f[i][j]表示決定了前i個掛飾並且有j個掛鉤時的vmax
就轉移,沒什麽可講的鴨,就
不選 f[i-1][j] 選f[i-1][max(j-a[i],0)+1]+b[i]
哦還是有倆要註意的點辣,分開港下qwq
第一個是關於那個max的
顯然的是,如果我們有一個掛飾,掛鉤特別特別多,超過了n,那它實際上有n就夠了(其實應該是不滿n的辣,先這麽說qwq)所以其實從max轉移來就是了
大概醬,其實還是有點兒無法理解的QAQ
如果實在無法理解我們可以醬
就是,我們可以不是從已知推出當前這個
而是,從當前這個推出能轉移到的
能懂嘛qwq
這樣就很好理解了鴨,轉移都差不多嘛,但是關於超過n實際有n就夠了這個理論的話就可以很簡單的實現不需要再拐彎辣qwq
就直接 min(n,j-1+a[i].w) 這樣就很好理解了嘛qwq
第二個是個需要註意的
就我們在轉移前要先對這個掛飾排序,根據掛鉤數排序
這個其實也能理解趴?因為這個其實是有點兒後效性的,就有點像之前做的那個什麽外星人做菜的dp(那個我也想寫題解qwq)
就是它是有後效性的,不知道能理解嘛?不能理解我明兒再來港qwq
所以就先排序,然後轉移然後就結束了呢!
#include<bits/stdc++.h> using namespace std; int f[2100][2100],n; bool o[2100][2100]; struct str{int w,v;}a[2100]; inline bool cmp(str n1,str n2){return n1.w>n2.w;} inline昂我放的是法二的代碼因為感覺法二挺好理解的法一那個我還是沒有很能理解QAQint read() { char ch=getchar();int x=0;bool y=1; while(ch!=‘-‘ && (ch<‘0‘ || ch>‘9‘))ch=getchar(); if(ch==‘-‘)ch=getchar(),y=0; while(ch>=‘0‘ && ch<=‘9‘)x=(x<<1)+(x<<3)+(ch^‘0‘),ch=getchar(); return y?x:-x; } int main() { n=read(); for(int i=1;i<=n;i++)a[i].w=read(),a[i].v=read(); sort(a+1,a+1+n,cmp); int ans=0;o[0][1]=true;memset(f,-63,sizeof(f));f[0][1]=0; for(int i=1;i<=n;i++) for(int j=0;j<=n;j++) { if(o[i-1][j] && j!=0) { int t=min(n,j-1+a[i].w); f[i][t]=max(f[i][t],f[i-1][j]+a[i].v); o[i][t]=1; } f[i][j]=max(f[i][j],f[i-1][j]); if(o[i-1][j]==1)o[i][j]=1; } for(int i=0;i<=n;i++)if(o[n][i])ans=max(ans,f[n][i]); printf("%d",ans); return 0; }
洛谷P4138 掛飾 背包