码迷,mamicode.com
首页 > 其他好文 > 详细

最近做的DP类题的总结~

时间:2014-10-15 14:18:20      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   color   io   os   ar   for   sp   

感觉自己DP确实太弱。。。

Codeforces Round #156 (Div. 1) A. Almost Arithmetical Progression

题意:在保持循序的情况下,从一个数组取出最多的数,这些数是交替出现的,例如,1,2,1,2,、。。

dp[i][j] 表示前i 个数,第 j 个数和第 i 个数被取出可以组成最长序列

我们用pre[i]记录 i 上一次出现的位置,这样就可以好好转移了。。。

bubuko.com,布布扣
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define mod 1000000007
#define maxn 1000010
#define pi acos(-1.0)
#define eps 1e-6
using namespace std;

int dp[4001][4001],a[4010],pre[maxn];
int num[maxn] ;

int main()
{
    int i,m,n,k,j ;
    int id,ans;
    while(scanf("%d",&n) != EOF)
    {
        for( i = 1 ; i <= n ;i++)
            scanf("%d",&a[i]) ;
        memset(pre,-1,sizeof(pre)) ;
        memset(num,0,sizeof(num)) ;
        ans=1;
        for(i = 1 ; i <= n ;i++)
        {
            id=pre[a[i]];
            num[a[i]]++;
            ans=max(num[a[i]],ans);
            pre[a[i]] = i ;
            for( j = 1 ; j < i ;j++)
            {
                if(id==-1)dp[j][i]=2 ;
                else if(j>id)dp[j][i] = 1+dp[id][j];
                else if(j<id)dp[j][i] = dp[j][id];
                ans=max(ans,dp[j][i]) ;
            }
        }
        cout <<ans<<endl;
    }
    return 0 ;
}
/256/problem/A
View Code

 

poj 1141 Brackets Sequence

题意: 给你一个字符串,你可以任意插入字符,使得塔变成回文串,长度要求最小,

然后把这个回文串输出来

dp[i][j]表示把 i-j变成回文串后的最短长度;

pre[x][y][2] 表示x,y从哪里转移过来的

然后 从 1,n经行 dfs,把需要增加字符和它匹配的位置标记

bubuko.com,布布扣
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define mod 1000000007
#define maxn 210
#define pi acos(-1.0)
#define eps 1e-6
#define INF 0x3f3f3f3f
using namespace std;

int dp[maxn][maxn],pre[maxn][maxn][2] ;
char a[maxn];
bool vi[maxn] ;
bool check(char a,char b)
{
    if(a==(&&b==)) return true;
    if(a==[&&b==]) return true;
    return false;
}
void out(char a)
{
    if(a==(||a==))printf("()") ;
    else printf("[]");
}
void dfs(int x,int y )
{
    if(x>y) return ;
    if(x>=y){vi[x]=true ;return;}
    int xx = pre[x][y][0],yy=pre[x][y][1] ;
   // cout << xx<<"--" <<yy<<endl;
   // cout<<x<<" "<<y<<endl;
    if(xx==x&&yy+1==y)
    {
        vi[y] = true;
        dfs(xx,yy) ;
    }
    else if(xx-1==x&&yy==y)
    {
        vi[x] = true;
        dfs(xx,yy);
    }
    else if(xx-1==x&&yy+1==y)
    {
        if(yy==xx)vi[xx]=1;
        dfs(xx,yy);
    }
    else
    {
        dfs(xx,yy) ;
        dfs(yy+1,y) ;
    }
}
int main()
{
    int cnt1,cnt2,n,i;
    int j , k , T,m ;
    while(gets(a+1) > 0 )
    {
        n = strlen(a+1) ;
        memset(dp,0,sizeof(dp));
        memset(vi,0,sizeof(vi));
        for( i = 1 ; i <= n ;i++)
        {
            dp[i][i]=2;
            for( j =i-1 ; j >= 1 ;j--)
            {
                dp[j][i] = dp[j][i-1]+2 ;
                pre[j][i][0]=j;
                pre[j][i][1]=i-1;
                if(dp[j+1][i]+2 < dp[j][i]){
                    dp[j][i] = dp[j+1][i]+2;
                    pre[j][i][0]=j+1;
                    pre[j][i][1]=i;
                }
                for( k = j+1 ; k < i ;k++)
                {
                    if(dp[j][k]+dp[k+1][i] < dp[j][i])
                    {
                        dp[j][i] = dp[j][k]+dp[k+1][i] ;
                        pre[j][i][0]=j;
                        pre[j][i][1]=k;
                    }
                }
                if(check(a[j],a[i])&& 2+dp[j+1][i-1] < dp[j][i])
                {
                    dp[j][i] = dp[j+1][i-1]+2;
                    pre[j][i][0]=j+1;
                    pre[j][i][1]=i-1;
                }
            }
        }
        dfs(1,n);
        for( i = 1 ; i <= n ;i++)
        {
            if(vi[i])out(a[i]) ;
            else printf("%c",a[i]);
        }
        puts("") ;
    }
    return 0 ;
}
View Code

poj 3280 Cheapest Palindrome

题意:每个字符都有删除它的代价增加它的代价,问最小的代价使得给出的字符串变成回文串

dp[i][j]表示,i-j变成字符串的最小代价

bubuko.com,布布扣
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define mod 1000000007
#define maxn 2010
#define pi acos(-1.0)
#define eps 1e-6
using namespace std;

int dp[maxn][maxn];
char a[maxn] ;
int cost1[210] ,cost2[210];
int main()
{
    int cnt1,cnt2,n,i;
    int j , k , T,m ;
    char s[5] ;
    while(scanf("%d%d",&n,&m) != EOF)
    {
         scanf("%s",a+1) ;
         for( i = 1 ; i <= n ;i++)
         {
             scanf("%s",s) ;
             scanf("%d%d",&cost1[s[0]],&cost2[s[0]]) ;
         }
         memset(dp,0x3f3f3f,sizeof(dp)) ;
         for( i = 1 ; i <= m;i++)
         {
             dp[i][i]=0;
             for( j = i-1 ; j >= 1 ;j--)
             {
                 dp[j][i] = dp[j][i-1]+min(cost1[a[i]],cost2[a[i]]) ;
                 dp[j][i] = min(dp[j][i],dp[j+1][i]+min(cost1[a[j]],cost2[a[j]])) ;
               //  cout <<j <<" " << i << " "<<dp[j][i] << endl;
                 if(a[i]==a[j])
                 {
                     dp[j][i] = min(dp[j][i],dp[j+1][i-1]) ;
                     if(i==j+1)dp[j][i]=0;
                 }
             }
         }
         cout <<dp[1][m] << endl;
    }
    return 0 ;
}
View Code

poj 2955 Brackets

 

题意:给出一个字符串,按先后循序不变选出一些字符组成一个回文串,要求这个回文串最长

dp[i][j]表示i-j可以选出最长的回文串

bubuko.com,布布扣
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define mod 1000000007
#define maxn 110
#define pi acos(-1.0)
#define eps 1e-6
using namespace std;

int dp[maxn][maxn];
char a[maxn] ;
bool check(char a,char b)
{
    if(a==(&&b==)) return true;
    if(a==[&&b==]) return true;
    return false;
}
int main()
{
    int cnt1,cnt2,n,i;
    int j , k , T ;
    while(scanf("%s",a+1) != EOF)
    {
        if(a[1]==e) break ;
        n = strlen(a+1) ;
        memset(dp,0,sizeof(dp)) ;
        for( j = 1 ; j <= n ;j++)
        {
            for( i = j-1; i >= 1 ;i--)
            {
                dp[i][j] = 0;
                if(check(a[i],a[j]))
                    dp[i][j] = max(dp[i][j],dp[i+1][j-1]+1) ;
                for(k = i ; k < j ; k++)
                    dp[i][j] = max(dp[i][k]+dp[k+1][j],dp[i][j]);
            }
        }
        cout << dp[1][n]*2 << endl;
    }
    return 0 ;
}
View Code

hdu 2476 String painter 

题意:每个你可以把a的一段居间刷成任意的一个字符,求把a变成 b 需要的最少刷的次数

dp[i][j] 表示把空串(相当于任意串)变成 b 中 i-j 子串的最小刷次数,

dp[i][j] = 1+dp[i+1][j] ;

如果 b[k]==b[i] ( k > i && k <= j ) 那么 b[i] 和 b[k] 可以一起刷出来 ,

dp[i][j] = min(dp[i][j],dp[i+1][k]+dp[k+1][j]) ; 

然后 a和b 的匹配, ans[i]表示把 1-i变成相同最小的改变次数

如果 a[i]==b[i] 那么ans[i]=ans[i-1];

不然,就去枚举 1-i 

bubuko.com,布布扣
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define mod 1000000007
#define maxn 210
#define pi acos(-1.0)
#define eps 1e-6
#define INF 0x3f3f3f3f
using namespace std;

int dp[maxn][maxn],ans[maxn] ;
char a[maxn],b[maxn] ;
int main()
{
    int cnt1,cnt2,n,i;
    int j , k , T,m ;
    while(scanf("%s%s",a+1,b+1) != EOF)
    {
         n = strlen(a+1) ;
         memset(dp,0,sizeof(dp)) ;
         for( i = 1 ; i <= n ;i++)
         {
             dp[i][i]=1;
             for( j = i-1 ; j >= 1 ;j--)
             {
                 dp[j][i] = 1+dp[j+1][i];
                 for( k = j+1 ; k <= i ;k++)if(b[j]==b[k])
                     dp[j][i] = min(dp[j][i],dp[j+1][k]+dp[k+1][i]) ;
                  //   cout << j <<" " <<i<<" "<<dp[j][i]<<endl;
             }
         }
         ans[0]=0;
         for( i= 1 ; i <= n ;i++)
         {
             if(a[i]==b[i])ans[i]=ans[i-1] ;
             else
             {
                 ans[i]=ans[i-1]+1;
                 for( j = i ; j >= 1 ;j--)
                    ans[i]=min(ans[i],ans[j-1]+dp[j][i]) ;
             }
         }
         cout <<ans[n]<<endl;
    }
    return 0 ;
}
View Code

poj 3661 Running 

题意:给出某个人n 分钟内每分钟可以跑步的距离,跑一分钟疲劳增加1 ,疲劳度不能超过 m  ,

他某个时候可以选择休息,休息一分钟可以疲劳度减1,不过等到疲劳度为 0 才可以继续跑步

在 第n 分钟结束时,他的疲劳度必须为 0 ,问最长可以跑多远

dp[i][j] 表示,第i 分钟,疲劳度为 j 时最远可以跑多远

如果选择跑步 dp[i][j] = dp[i-1][j-1]+a[i] 

不过 dp[i-1][j]不能转移到它,因为必须休息到0才能跑,

如果转移了,那么下一次用到它的转移就会出错。

dp[i][0] = dp[i-1][0] ;

或者第 j 分钟 选择休息 dp[i][0] = max(dp[i][0],dp[j][i-j]) ;

bubuko.com,布布扣
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define mod 1000000007
#define maxn 10010
#define pi acos(-1.0)
#define eps 1e-6
#define INF 0x3f3f3f3f
using namespace std;

int dp[10001][510];
int a[maxn];
int main()
{
    int cnt1,cnt2,n,i;
    int j , k , T,m ;
    while(scanf("%d%d",&n,&m) != EOF)
    {
         for( i = 1 ; i <= n ;i++)
            scanf("%d",&a[i]) ;
         memset(dp,0,sizeof(dp)) ;
         for( i = 1 ; i <= n ;i++)
         {
             for( j = 1 ; j <= m ;j++)
             {
                 dp[i][j]=dp[i-1][j-1]+a[i];
             }
             dp[i][0]=max(dp[i-1][0],dp[i-1][1]) ;
             for(int k=1;k<=m;k++)if(i-k>=0)
                dp[i][0]=max(dp[i][0],dp[i-k][k]);
         }
         cout << dp[n][0] << endl;
    }
    return 0 ;
}
View Code

 

最近做的DP类题的总结~

标签:style   blog   http   color   io   os   ar   for   sp   

原文地址:http://www.cnblogs.com/20120125llcai/p/4024773.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!