• CQOI2007 涂色


    传送门

    这道题才应该是标准的区间DP!

    其实这个题用一种神奇的算法瞎写就能得80……一会可以附上参考代码……如果有神犇愿意帮助debug不胜感激……

    考虑区间DP。用dp[i][j]表示将区间[i,j]涂好需要使用的最少的颜色种数。

    既然如此,dp方程就很显然,因为毕竟区间dp的思想就是先算小区间再合并成大区间。所以我们先从小到大枚举区间长度,之后再枚举区间端点。然后,因为一个大区间可以看作由两个小区间合并而成(因为小区间的状态是全部被染好的,所以是可以直接合并成大区间的),所以我们枚举区间断点。

    那么dp[i][j] = min(dp[i][k] + dp[k+1][j],dp[i][j]),其中k由i+1枚举到j即可。

    还有一点就是,如果当前区间枚举的两个点所对应的元素相同,那么直接有dp[i][j] = min(dp[i][j],dp[i+1][j-1] + 1).这个也是很显然的。

    既然如此就可以上代码了,很简短。(80pts的在前)

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define rep(i,a,n) for(ll i = a;i <= n;i++)
    #define per(i,n,a) for(ll i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    const int M = 105;
    typedef long long ll;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    char s[100];
    int dp[105][105],len;
    int main()
    {
        scanf("%s",s+1);
        len = strlen(s+1);
    //    printf("%d
    ",len);
        memset(dp,127/3,sizeof(dp));
        rep(i,1,len) dp[i][i] = 1;
        rep(p,0,len)
        rep(i,1,len-p)
        {
            if(s[i] == s[i+1]) dp[i][i+p] = min(dp[i+1][i+p],dp[i][i+p]);
            if(s[i+p-1] == s[i+p]) dp[i][i+p] = min(dp[i][i+p],dp[i][i+p-1]);
            if(s[i] == s[i+p]) 
            {
                if(s[i] == s[i+1] && s[i+p-1] == s[i+p]) dp[i][i+p] = min(dp[i][i+p],dp[i+1][i+p-1]);
                else dp[i][i+p] = min(min(dp[i][i+p],dp[i+1][i+p-1]+1),min(dp[i+1][i+p],dp[i][i+p-1]));
            }
            dp[i][i+p] = min(dp[i][i+p],dp[i+1][i+p] + 1);
            dp[i][i+p] = min(dp[i][i+p],dp[i][i+p-1] + 1);
            dp[i][i+p] = min(dp[i][i+p],dp[i+1][i+p-1] + 2);
        }
        printf("%d
    ",dp[1][len]);
        return 0;
    }

    下面的是AC代码:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define rep(i,a,n) for(ll i = a;i <= n;i++)
    #define per(i,n,a) for(ll i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    const int M = 105;
    typedef long long ll;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    
    char s[100];
    int dp[105][105],len;
    int main()
    {
        scanf("%s",s+1);
        len = strlen(s+1);
        memset(dp,127/3,sizeof(dp));
        rep(i,1,len) dp[i][i] = 1;
        rep(p,1,len-1)
        rep(i,1,len-p)
        {
            if(s[i] == s[i+p]) dp[i][i+p] = min(dp[i+1][i+p],dp[i+1][i+p-1]+1);
            else rep(k,i,i+p-1) dp[i][i+p] = min(dp[i][i+p],dp[i][k]+dp[k+1][i+p]);
        }
        printf("%d
    ",dp[1][len]);
        return 0;
    }
  • 相关阅读:
    改Android手机定位位置
    设计模式-行为型模式
    设计模式-结构型模式
    设计模式-创建型模式
    LoadRunner改脚本
    交互设计流程
    java正则过滤特殊字符
    js正则表达式判断非法字符 .(转)
    <BEA-141281> <unable to get file lock, will retry ...> (转)
    JAVA调用打印机打印指定文件
  • 原文地址:https://www.cnblogs.com/captain1/p/9539254.html
Copyright © 2020-2023  润新知