• K


    题目大意:

    给定两个长度为N的01字符串,每一次选取其中的一个依次从左往右读,需要保证已经读过的0和1的个数差小于等于k,试问:这样的读字符串方案是否存在?如果存在,第一个字符串从左往右读一位输出1,第二个字符串从左往右读一位输出2,输出字典序最小的输出方案。

    方法1:DFS

    这个想法比较自然。首先构造出搜索图map[maxn][maxn]。定义扫描状态(i,j)表示当前第一个字符串扫描到了第i位,第二个字符串扫描到了第j位。(i,j)合法当且仅当当前状态下已经扫描过的01个数差小于等于k。如果(i,j)合法,置map[i][j] = 1;否则map[i][j] = 0。这样就得到了一张由01组成的图。以测试数据

    4 1

    0011

    0110 为例。得到的搜索图map为:

    1 1 1 1 1

    1 0 1 1 1

    0 0 0 1 0

    1 0 1 1 1

    1 1 1 1 1

    现在整个问题转化为找到一条可行的“1”路径,使得一个点能够从图的左上角移动到右下角。注意题目要求字典序最小的输出方案,所以深搜时以“向下”移动优先。

    注意深搜的过程。已经回溯过的点肯定不用再走,所以置一个visit矩阵有助于减小搜索量。

       1: /*
       2: sample output:
       3: 22121112
       4: Poor Alice
       5: */
       6: #include <iostream>
       7: #include <cstdio>
       8: #include <cstring>
       9: #include <cmath>
      10: using namespace std;
      11: const int maxn = 1010;
      12: char str1[maxn], str2[maxn], result[2*maxn];
      13: bool map[maxn][maxn];
      14: int cnt1[maxn],cnt2[maxn];
      15: bool visit[maxn][maxn];
      16: int n,k;
      17: bool flag;
      18: void dfs(int u, int v)
      19: {
      20:     if(n == v && n == u)
      21:     {
      22:         flag = true;
      23:         printf("%s\n",result);
      24:         return;
      25:     }
      26:     if(map[u+1][v] == 1 && !visit[u+1][v] && !flag)
      27:     {
      28:         //if(flag) return;
      29:         result[u+v] = '1';
      30:         dfs(u+1,v);    
      31:     }
      32:     if(map[u][v+1] == 1 && !visit[u][v+1] && !flag)
      33:     {
      34:         //if(flag) return;
      35:         result[u+v] = '2';
      36:         dfs(u,v+1);    
      37:     }
      38:     visit[u][v] =  1;
      39:     if(u==0 && v == 0 && !flag) printf("Poor Alice\n");
      40:     return;
      41: }
      42:  
      43: int main()
      44: {
      45:     //freopen("test.txt","r",stdin);
      46:     while(scanf("%d%d",&n,&k)!= EOF)
      47:     {
      48:         memset(map,0,sizeof(map));
      49:         scanf("%s%s",str1,str2);
      50:         cnt1[0] = 0;
      51:         cnt2[0] = 0;
      52:         for(int i=0;i<n;++i)
      53:         {
      54:             if(str1[i] == '1')
      55:                 cnt1[i+1] = cnt1[i] + 1;
      56:             else cnt1[i+1] = cnt1[i] - 1;
      57:             if(str2[i] == '1')
      58:                 cnt2[i+1] = cnt2[i] + 1;
      59:             else cnt2[i+1] = cnt2[i] - 1;
      60:         }
      61:         for(int i=0;i<=n;++i)
      62:             for(int j = 0;j<=n;++j)
      63:             {
      64:                 int temp = cnt1[i] + cnt2[j];
      65:                 if(abs((double)temp) <= k)
      66:                     map[i][j] = 1;
      67:             }
      68:         result[2*n-1] = '\0';
      69:         /*for(int i=0;i<=n;++i)
      70:         {
      71:             for(int j=0;j<=n;++j)
      72:                 cout<<map[i][j]<<' ';
      73:             cout<<endl;
      74:         }*/
      75:         flag = false;
      76:         memset(visit,0,sizeof(visit));
      77:         dfs(0,0);    
      78:     }
      79:     return 0;
      80: }

    方法二:DP。

    令ok[i][j]=1表示从第一个字符串的第i个字符,第二个字符串的第j个字符开始可以扫描完整个字符串。那么可以建立DP递归方程:

    ok[i][j-1] = 1 iff ok[i][j] && map[i][j-1]

    ok[i-1][j] = 1 iff ok[i][j] && map[i-1][j]

    这个方法没有方法一自然,因为逆推不太容易想到。

       1: #include <iostream>
       2: #include <cstdio>
       3: #include <cstring>
       4: #include <cmath>
       5: using namespace std;
       6: const int maxn = 1010;
       7: char str1[maxn], str2[maxn];
       8: bool map[maxn][maxn],ok[maxn][maxn];
       9: int cnt1[maxn],cnt2[maxn];
      10: bool visit[maxn][maxn],flag;
      11: int n,k;
      12: int main()
      13: {
      14:     //freopen("test.txt","r",stdin);
      15:     while(scanf("%d%d",&n,&k)!= EOF)
      16:     {
      17:         flag = true;
      18:         memset(map,0,sizeof(map));
      19:         memset(ok,0,sizeof(ok));
      20:         scanf("%s%s",str1,str2);
      21:         cnt1[0] = 0;
      22:         cnt2[0] = 0;
      23:         for(int i=0;i<n;++i)
      24:         {
      25:             if(str1[i] == '1')
      26:                 cnt1[i+1] = cnt1[i] + 1;
      27:             else cnt1[i+1] = cnt1[i] - 1;
      28:             if(str2[i] == '1')
      29:                 cnt2[i+1] = cnt2[i] + 1;
      30:             else cnt2[i+1] = cnt2[i] - 1;
      31:         }
      32:         for(int i=0;i<=n;++i)
      33:             for(int j = 0;j<=n;++j)
      34:             {
      35:                 int temp = cnt1[i] + cnt2[j];
      36:                 if(abs((double)temp) <= k)
      37:                     map[i][j] = 1;
      38:             }
      39:         if(!map[n][n])
      40:         {
      41:             printf("Poor Alice\n");
      42:             continue;
      43:         }
      44:         ok[n][n] = 1;
      45:         for(int i = n;i>=0;--i)
      46:             for(int j = n;j>=0;--j)
      47:             {
      48:                 if(ok[i][j] && map[i][j-1] && j)
      49:                     ok[i][j-1] = 1;
      50:                 if(ok[i][j] && map[i-1][j] && i)
      51:                     ok[i-1][j] = 1;
      52:             }
      53:         if(!(ok[0][1] || ok[1][0])) 
      54:             {printf("Poor Alice\n");continue;}
      55:         int i=0,j=0;
      56:         while(i!=n || j!=n)
      57:         {
      58:             if(ok[i+1][j])
      59:             {
      60:                 printf("1");
      61:                 i++;
      62:             }
      63:             else if(ok[i][j+1])
      64:             {
      65:                 printf("2");
      66:                 j++;
      67:             }
      68:         }
      69:         printf("\n");
      70:  
      71:     }
      72:     return 0;
      73: }
  • 相关阅读:
    BZOJ4401 块的计数
    poj2914 Minimum Cut 全局最小割模板题
    无向图求最小割集
    HDU3232 Crossing Rivers 数学期望问题
    poj1386 字符串类型的一笔画问题 欧拉回路
    HDU3018 几笔画(非1笔)
    欧拉路&&欧拉回路 概念及其练习
    欧拉回路基础 HDU1878 欧拉回路||并差集
    我的明天在何处
    哈夫曼树讲解
  • 原文地址:https://www.cnblogs.com/bovine/p/2393225.html
Copyright © 2020-2023  润新知