1. 程式人生 > >[學習筆記]區間dp

[學習筆記]區間dp

區間 \(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;
}