zoukankan      html  css  js  c++  java
  • fzu2158

    http://acm.fzu.edu.cn/problem.php?pid=2158

    在密室逃脱游戏中,大家被困在一个密室中,为了逃出密室,需要找到正确的数字密码,于是大家分头行动,分别找到了密码的子序列,而后大家将得到的线索集中整理分析,大家想知道密码最少是多少位。第一行输入一个整数T,表示数据组数。接下来T组数据,对于每组数据,第一行输入一个整数n (1<=n<=7),表示有n个人,接下来第2到n+1行每行输入一串数字,分别表示第i个人得到的密码子序列(长度<=6)。

    1
    3
    123
    14
    21
    5
    比赛的时候是3秒,以前在做搜索的遇到过类似的题目,我是用A*过的.....在这里被卡住了
    代码:
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int len[8],n,flag,p,dp[8][10];
    char s[8][8];
    
    int deal()
    {
        int maxn=0;
        for(int i=0;i<n;i++)
        maxn=max(maxn,len[i]);
        return maxn;
    }
    int deal1()
    {
        int sum=0;
        for(int j=0;j<=9;j++)
        {
            int maxn=0;
            for(int i=0;i<n;i++)
            {
                maxn=max(maxn,dp[i][j]);
            }
            sum+=maxn;
        }
        return sum;
    }
    void dfs(int step)
    {
        if(flag==1)
        return;
        int x=deal();
        int y=deal1();
        if(x==0)
        {
            flag=1;
            return;
        }
        if(step+x>p||step+y>p)
        return;
        for(int i=0;i<n;i++)
        {
            if(len[i]==0)  continue;
            int f[10],cnt=0;
            int tmp=len[i]-1;
            int xx=s[i][tmp]-'0';
            for(int j=0;j<n;j++)
            {
                if(len[j]==0)  continue;
                int tmp1=len[j]-1;
                if(s[i][tmp]==s[j][tmp1])
                {
                    len[j]--;
                    f[cnt++]=j;
                    dp[j][xx]--;
                }
            }
            if(cnt)
            {
                dfs(step+1);
                for(int i=0;i<cnt;i++)
                {
                    int tmp2=f[i];
                    len[tmp2]++;
                    dp[tmp2][xx]++;
                }
            }
        }
    }
    int main()
    {
        int text;
        scanf("%d",&text);
        while(text--)
        {
            scanf("%d",&n);
            memset(dp,0,sizeof(dp));
            for(int i=0;i<n;i++)
            {
                scanf("%s",s[i]);
                len[i]=strlen(s[i]);
                for(int j=0;j<len[i];j++)
                {
                    int tmp=s[i][j]-'0';
                    dp[i][tmp]++;
                }
            }
            p=flag=0;
            p=max(deal1(),deal());
            while(1)
            {
                dfs(0);
                if(flag==1)
                break;
                p++;
            }
            printf("%d
    ",p);
        }
        return 0;
    }
    

      比赛完了,挂出来是1s的时候,在朋友的提醒下,用dp过的,简单的说下思路:

    我开了7维dp,每一维分别对应这一维的字符串还有多少个字母没有匹配完的情况下所需要的最少字符个数。

    我采取的是从n个字符串的最后开始往前面匹配的,每次找一个字符,看它是否与其它几个字符串相应位置上的字符相等,相等就-1,我所采取的方法是记忆化搜索,感觉这样容易把思路提现出来.......下面是代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    #define inf (1<<28)
    int dp[7][7][7][7][7][7][7],n,t[8];
    char s[8][10];
    
    int dfs(int a,int b,int c,int d,int e,int f,int g)
    {
        if(a==0&&b==0&&c==0&&d==0&&e==0&&f==0&&g==0)
        return 0;
        if(dp[a][b][c][d][e][f][g]) return dp[a][b][c][d][e][f][g];
        //int h[7];
        /*h[0]=a;
        h[1]=b;
        h[2]=c;
        h[3]=d;
        h[4]=e;
        h[5]=f;*/
        int minx=inf;
        //if(a>0)
        for(int j=0;j<n;j++)
        {
            if(t[j]==0) continue;
            int f[7],cnt=0;
            int tmp=t[j];
            for(int i=0;i<n;i++)
            {
                if(t[i]==0) continue;
                int tmp1=t[i];
                if(s[i][tmp1-1]==s[j][tmp-1])
                {
                    //if(a==3&&b==2&&c==2)
                    //printf("%c %c %d %d
    ",s[i][t[i]-1],s[j][t[j]-1],i,j);
                    f[cnt++]=i;
                    t[i]--;
                }
            }
            //if(a==3&&b==2&&c==2)
            //printf("%d %d %d
    ",t[0],t[1],t[2]);
            //if(t[0]==3&&t[1]==1&&t[2]==1)
            //printf("%c
    ",s[j][t[j]-1]);
            if(cnt)
            {
                int p=1+dfs(t[0],t[1],t[2],t[3],t[4],t[5],t[6]);
                minx=min(minx,p);
                //if(a==2&&b==1&&c==2)
                //printf("%d %d %d %d %d
    ",t[0],t[1],t[2],minx,p-1);
                for(int i=0;i<cnt;i++)
                {
                    int x=f[i];
                    t[x]++;
                }
            }
        }
        dp[a][b][c][d][e][f][g]=minx;
        //printf("%d %d %d %d
    ",a,b,c,minx);
        return minx;
    }
    int main()
    {
        int text;
        scanf("%d",&text);
        while(text--)
        {
            scanf("%d",&n);
            memset(dp,0,sizeof(dp));
            memset(t,0,sizeof(t));
            for(int i=0;i<n;i++)
            {
                scanf("%s",s[i]);
                t[i]=strlen(s[i]);
                //printf("%d
    ",t[i]);
            }
            printf("%d
    ",dfs(t[0],t[1],t[2],t[3],t[4],t[5],t[6]));
            //for(int i=0;i<n;i++)
            //printf("%d	",t[i]);
        }
        return 0;
    }
    

      

     
  • 相关阅读:
    好用的javascript eclipse插件Aptana
    汉字字符串转换成十六进制byte数组,一个汉字存到两个byte里面,大整数存到两个byte里面
    三星 平板手机电脑 Galaxytab2忘记开机密码解决方法
    java float 加减精度问题
    android 增加Addon属性支持的方法
    基于jquery的kendoUI 可以实现快速开发,节省大量web UI开发工作量
    zdz工具箱v1.5 android版本发布了,集成各种个人生活中常用的工具,方便日常使用管理
    存储联系人信息(进程com.motorola.contacts)意外停止 事件提醒eventreminder异常 处理方法
    playframework 同时运行多个项目的方法修改默认端口号
    免费的Git私有代码托管服务
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/3632665.html
Copyright © 2011-2022 走看看