zoukankan      html  css  js  c++  java
  • 第五届山东省ACM Colorful Cupcakes(Dp)

    Colorful Cupcakes

    给出ABC三种颜色的个数,求相邻颜色不相同,首尾颜色不相同的串的个数。

    思路:

    开始的时候感觉就是个搜索,但是一想简单搜索肯定超时,dp的话也没找出递推公式,竟让把记忆化搜索给忘了,悲哀。。。
    dp[i][a][b][k]表示前i个位置A有a个B有b个,当前位置颜色是k的个数。
    假设当前颜色是红色,也就是0(自己定) 
    dp[i][a][b][k]=∑dp[i−1][a−1][b][ii],    ii = 1,2,3. ii != k,ii是上一个位置的颜色,不能和k相同。

    从后往前搜索

    #include <stack>  
    #include <cstdio>  
    #include <list>  
    #include <set>  
    #include <iostream>  
    #include <string>  
    #include <vector>  
    #include <queue>  
    #include <functional>  
    #include <cstring>  
    #include <algorithm>  
    #include <cctype>  
    #include <string>  
    #include <map>  
    #include <cmath>  
    using namespace std;  
    const int MAXN = 50 + 3;  
    const int MOD = 1e9 + 7;  
    char str[100];  
    int cnt[3];  
    int dp[MAXN][MAXN][MAXN][3];  
    int lastColor ;  
    ///记忆化搜索  也就是算法设计中所说的备忘录方法  
    int DFS(int pre, int a, int b, int k)///前pre位有a个A色b个绿色,此位是k颜色的个数  
    {  
        if (dp[pre][a][b][k] != -1) return dp[pre][a][b][k];  
        if (a < 0 || b < 0 || pre-a-b < 0) return 0;  
        if (pre == 1 && k == lastColor)   return 0;    ///如果第一位和最后一位相同,0种情况  
        if (pre == 1)   return dp[pre][a][b][k] = ((a && k == 0) || (b && k == 1) || (pre-a-b && k == 2));  
        ///有可能出现第一位本来已经没多余的某种颜色了,却能走到这一步。排除  
        ///因为枚举前一位是什么颜色的时候并没考虑那种颜色还有没有剩余  
        int ans = 0;  
        for (int ii = 0; ii < 3; ii++)  ///前一位是什么颜色  
        {  
            if (k == ii) continue;  
            if (k == 0) ans = (ans + DFS(pre-1, a-1, b, ii)) % MOD;  
            if (k == 1) ans = (ans + DFS(pre-1, a, b-1, ii)) % MOD;  
            if (k == 2) ans = (ans + DFS(pre-1, a, b, ii)) % MOD;  
        }  
        return dp[pre][a][b][k] = ans;  
    }  
    int main()  
    {  
        int T;  
        scanf("%d", &T);  
        while (T--)  
        {  
            scanf("%s", str);  
            memset(dp,-1,sizeof(dp));  
            memset(cnt,0,sizeof(cnt));  
            int len = strlen(str);  
            for (int i = 0; i < len; i++)  
                cnt[str[i]-'A']++;  
            int ans = 0;  
            for (int i = 0; i < 3; i++)     ///最后一位是什么颜色  
            {  
                memset(dp,-1,sizeof(dp));  
                lastColor=i;  
                ans = (ans + DFS(len, cnt[0], cnt[1], i)) % MOD;  
            for(int i=1;i<=len;i++)  
                for(int j=1;j<=len;j++)  
                 for(int x=1;x+j<=len;x++)  
                  for(int k=0;k<3;k++)  
                    if(dp[i][j][x][k]!=-1)  
                  cout<<"dp["<<i<<"]["<<j<<"]["<<x<<"]["<<k<<"]"<<dp[i][j][x][k]<<endl;  
            }  
      
            printf("%d
    ", ans);  
        }  
        return 0;  
    }  


    感觉从后往前写有点绕,自己敲了个从前往后的,大同小异。

    #include<cstdio>  
    #include<cstring>  
    #include<cmath>  
    #include<cstdlib>  
    #include<iostream>  
    #include<algorithm>  
    #include<vector>  
    #include<map>  
    #include<queue>  
    #include<stack>  
    #include<string>  
    #include<map>  
    #include<set>  
    #include<ctime>  
    #define eps 1e-6  
    #define MAX 100005  
    #define INF 0x3f3f3f3f  
    #define LL long long  
    #define pii pair<string,int>  
    #define rd(x) scanf("%d",&x)  
    #define rd2(x,y) scanf("%d%d",&x,&y)  
    const int dir[][2] = { {-1, 0}, {0, -1}, { 1, 0 }, { 0, 1 } };  
    using namespace std;  
      
    const int MAXN = 50 + 3;  
    const int MOD = 1e9 + 7;  
    char str[100];  
    int cnt[3];  
    int dp[MAXN][MAXN][MAXN][3];  
    int firstColor,len;  
    ///记忆化搜索  也就是算法设计中所说的备忘录方法  
    int DFS(int pre, int a, int b, int k)///前pre位有a个A色 b个B色,k是本次要搜索的颜色标志  
    {  
        if ((k==0 && a+1 > cnt[0]) || (k==1 && b+1 > cnt[1]) || (k==2 && pre-a-b > cnt[2]))  return 0;  
        if (dp[pre][a][b][k] != -1) return dp[pre][a][b][k];  
        if (pre == len && k == firstColor)  return 0;    ///如果第一位和最后一位相同,0种情况  
        if (pre == len)  return ((a+1<=cnt[0] && k == 0) || (b+1<=cnt[1] && k == 1) || (pre-a-b <= cnt[2] && k == 2));  
        ///有可能出现第一位本来已经没多余的某种颜色了,却能走到这一步。排除  
        ///因为枚举前一位是什么颜色的时候并没考虑那种颜色还有没有剩余  
        int ans = 0;  
        for (int ii = 0; ii < 3; ii++)  ///前一位是什么颜色  
        {  
            if (k == ii) continue;  
            if (k == 0) ans = (ans + DFS(pre+1, a+1, b, ii)) % MOD;  
            if (k == 1) ans = (ans + DFS(pre+1, a, b+1, ii)) % MOD;  
            if (k == 2) ans = (ans + DFS(pre+1, a, b, ii)) % MOD;  
        }  
        return dp[pre][a][b][k] = ans;  
    }  
      
    int main()  
    {  
        int T;  
        scanf("%d", &T);  
        while (T--)  
        {  
            scanf("%s", str);  
            memset(dp,-1,sizeof(dp));  
            memset(cnt,0,sizeof(cnt));  
            len = strlen(str);  
            for (int i = 0; i < len; i++)  
                cnt[str[i]-'A']++;  
            int ans = 0;  
            for (int i = 0; i < 3; i++)     ///最后一位是什么颜色  
            {  
                memset(dp,-1,sizeof(dp));  
                firstColor=i;  
                ans = (ans + DFS(1, 0, 0, i)) % MOD;  
            }  
            printf("%d
    ", ans);  
        }  
        return 0;  
    }  



  • 相关阅读:
    多线程之同步代码块与同步函数
    图片上传客户端与服务端
    tcp上传学习二--文本文件上传
    javaScript编写9*9口诀
    tcp聊天
    udp聊天室--简易
    往sencha.cmd中恢复设计项时,不论是系统的还是应用的,恢复进去之后都应该一键发布到前端
    一个设计项上的按钮调另一个设计项的列表界面,同时加筛选条件
    点击【****】设计项上的某个按钮,直接调出另一个设计项的【编辑界面】
    前端向后端发送请求,后端返回的一个值的请求的ajax.get();方法
  • 原文地址:https://www.cnblogs.com/zswbky/p/6717960.html
Copyright © 2011-2022 走看看