[學習筆記]區間dp
阿新 • • 發佈:2018-11-19
區間 \(dp\)
1、[HAOI2008]玩具取名
\(f[l][r][W/I/N/G]\) 表示區間 \([l,r]\) 中能否壓縮成 \(W/I/N/G\)
\(Code\ Below:\)
#include <bits/stdc++.h> using namespace std; const int maxn=200+10; int n,W,I,N,G,le[maxn],fir[maxn],sec[maxn],f[maxn][maxn][4],cnt; char s[maxn]; int check(char ch){ if(ch=='W') return 0; if(ch=='I') return 1; if(ch=='N') return 2; return 3; } char toalpha(int i){ if(i==0) return 'W'; if(i==1) return 'I'; if(i==2) return 'N'; return 'G'; } int main() { scanf("%d%d%d%d",&W,&I,&N,&G); char ch; for(int i=1;i<=W;i++){ ch=getchar(); while(!isalpha(ch)) ch=getchar(); le[++cnt]=0;fir[cnt]=check(ch); ch=getchar();sec[cnt]=check(ch); } for(int i=1;i<=I;i++){ ch=getchar(); while(!isalpha(ch)) ch=getchar(); le[++cnt]=1;fir[cnt]=check(ch); ch=getchar();sec[cnt]=check(ch); } for(int i=1;i<=N;i++){ ch=getchar(); while(!isalpha(ch)) ch=getchar(); le[++cnt]=2;fir[cnt]=check(ch); ch=getchar();sec[cnt]=check(ch); } for(int i=1;i<=G;i++){ ch=getchar(); while(!isalpha(ch)) ch=getchar(); le[++cnt]=3;fir[cnt]=check(ch); ch=getchar();sec[cnt]=check(ch); } scanf("%s",s+1);n=strlen(s+1); for(int i=1;i<=n;i++) f[i][i][check(s[i])]=1; for(int i=n-1;i>=1;i--) for(int j=i+1;j<=n;j++) for(int k=i;k<j;k++) for(int l=1;l<=cnt;l++) if(f[i][k][fir[l]]&&f[k+1][j][sec[l]]) f[i][j][le[l]]=1; int flag=1; for(int i=0;i<4;i++) if(f[1][n][i]){ flag=0; putchar(toalpha(i)); } if(flag) printf("The name is wrong!"); putchar('\n'); return 0; }
2、[SCOI2009]粉刷匠
兩次 \(dp\)
第一次 \(dp\) 出每一條木板粉刷 \(k\) 次最多能刷多少格子
第二次 \(dp\) 出最終答案,也就是把第一次 \(dp\) 的結果合併一下
\(Code\ Below:\)
#include <bits/stdc++.h> using namespace std; const int maxn=50+10; int n,m,t,sum[maxn],f[maxn][maxn],dp[maxn][maxn*maxn]; char a[maxn]; int main() { scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++){ scanf("%s",a+1); memset(f,128,sizeof(f)); for(int j=1;j<=m;j++) sum[j]=sum[j-1]+(a[j]=='1'); for(int j=0;j<=m;j++) f[j][0]=0; for(int j=1;j<=m;j++) for(int x=0;x<m;x++) for(int k=1;k<=j;k++) f[j][k]=max(f[j][k],f[x][k-1]+max(sum[j]-sum[x],j-x-(sum[j]-sum[x]))); for(int j=1;j<=t;j++){ int limit=min(j,m); for(int k=0;k<=limit;k++) dp[i][j]=max(dp[i][j],dp[i-1][j-k]+f[m][k]); } } int ans=0; for(int i=1;i<=t;i++) ans=max(ans,dp[n][i]); printf("%d\n",ans); return 0; }