• Luogu P1039 侦探推理(模拟+枚举)


    P1039 侦探推理

    题意

    题目描述

    明明同学最近迷上了侦探漫画《柯南》并沉醉于推理游戏之中,于是他召集了一群同学玩推理游戏。游戏的内容是这样的,明明的同学们先商量好由其中的一个人充当罪犯(在明明不知情的情况下),明明的任务就是找出这个罪犯。接着,明明逐个询问每一个同学,被询问者可能会说:

    P3802

    证词中出现的其他话,都不列入逻辑推理的内容。

    明明所知道的是,他的同学中有NN个人始终说假话,其余的人始终说真。

    现在,明明需要你帮助他从他同学的话中推断出谁是真正的凶手,请记住,凶手只有一个!

    输入输出格式

    输入格式:

    输入由若干行组成,第一行有三个整数,(M(1leq Mleq 20),N(1leq Nleq M))(P(1leq Pleq 100))(M)是参加游戏的明明的同学数,(N)是其中始终说谎的人数,(P)是证言的总数。

    接下来(M)行,每行是明明的一个同学的名字(英文字母组成,没有空格,全部大写)。

    往后有(P)行,每行开始是某个同学的名宇,紧跟着一个冒号和一个空格,后面是一句证词,符合前表中所列格式。证词每行不会超过(250)个字符。

    输入中不会出现连续的两个空格,而且每行开头和结尾也没有空格。

    输出格式:

    如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是罪犯,则输出"Cannot Determine";如果程序判断出没有人可能成为罪犯,则输出"Impossible"

    输入输出样例

    输入样例#1:

    3 1 5
    MIKE
    CHARLES
    KATE
    MIKE: I am guilty.
    MIKE: Today is Sunday.
    CHARLES: MIKE is guilty.
    KATE: I am guilty.
    KATE: How are you??
    

    输出样例#1:

    MIKE
    

    思路

    我没啥题做了,求推荐好题。 --WYL
    P1039. --Uranus

    其实根本不是好题,这题太屑了。

    这道题的毒瘤从输入开始:输入证词是什么鬼啊,还要判断输入是否合法,这个被我大力模拟写过去了:

    while(p--)
    {
        string str;
        getline(cin,str);
        string now;
        int p;
        for(p=0;p<str.length();p++)
            if(str[p]==':') break;
            else now+=str[p];
        int id=0;
        for(int i=1;i<=m;i++)
            if(name[i]==now)//判断当前是谁
            {
                id=i;
                break;
            }
        p+=2;
        now="";
        while(isalpha(str[p])) now+=str[p++];//得到一个单词
        p++;
        if(now=="I")//说的是自己
        {
            now="";
            while(isalpha(str[p])) now+=str[p++];
            p++;
            if(now=="am")
            {
                now="";
                while(isalpha(str[p])) now+=str[p++];
                if(now=="guilty"&&str[p]=='.') think[id][id]=1;//记录某人认为的犯人的情况
                else if(now=="not")
                {
                    p++;
                    now="";
                    while(isalpha(str[p])) now+=str[p++];
                    if(now=="guilty"&&str[p]=='.') think[id][id]=2;
                }
            }
        }
        else if(now=="Today")//说的是星期
        {
            now="";
            while(isalpha(str[p])) now+=str[p++];
            p++;
            if(now=="is")
            {
                now="";
                while(isalpha(str[p])) now+=str[p++];
                p++;
                for(int i=1;i<=7;i++)
                    if(now==week[i])
                    {
                        day[id][i]=true;//记录某人认为今天是星期几
                        break;
                    }
            }
        }
        else//说的是别人
        {
            int to=0;
            for(int i=1;i<=m;i++)
                if(name[i]==now)
                {
                    to=i;
                    break;
                }
            if(to)
            {
                now="";
                while(isalpha(str[p])) now+=str[p++];
                p++;
                if(now=="is")
                {
                    now="";
                    while(isalpha(str[p])) now+=str[p++];
                    if(now=="guilty"&&str[p]=='.') think[id][to]=1;
                    else if(now=="not")
                    {
                        p++;
                            now="";
                            while(isalpha(str[p])) now+=str[p++];
                            if(now=="guilty"&&str[p]=='.') think[id][to]=2;
                    }
                }
            }
        }
    }
    

    接下来大力枚举说谎的人和说真话的人其实也还好写,然后就是判断当前状况是否可行,特别的难写。在这里,我用ans1记录当前是否已经找到了解,用ans2记录当前找到的犯人:

    void judge()
    {
        memset(vis,false,sizeof vis);
        int cnt=0,_cnt=0,guilt=0,true_day=0;
        for(int i=1;i<=m;i++)//判断犯人
            if(lie[i])//这是个说谎的人
                for(int j=1;j<=m;j++)//改假话为真话
                    if(think[i][j]==1) think[i][j]=2;
                    else if(think[i][j]==2) think[i][j]=1;
        for(int i=1;i<=m;i++)//判断星期
        {
            if(lie[i]) continue;
            int hjj=0;
            for(int j=1;j<=7;j++)
                if(day[i][j])
                {
                    if(hjj) goto NoSolution;
                    else hjj=j;
                }
            if(!true_day) true_day=hjj;
            else if(hjj&&hjj!=true_day) goto NoSolution;//无解
        }
        if(true_day)
            for(int i=1;i<=m;i++)
                if(lie[i]&&day[i][true_day]) goto NoSolution;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(think[j][i])
                {
                    int state=think[j][i];
                    for(int k=j+1;k<=m;k++) if(think[k][i]&&think[k][i]!=state) goto NoSolution;//无解
                    if(state==1) guilt=i,cnt++;//记录嫌疑犯
                    else if(state==2) _cnt++,vis[i]=true;//记录不是嫌疑犯的人
                    break;
                }
        if(cnt==1)
        {
            if(!ans1) ans1=1,ans2=guilt;
            else if(ans1==1&&ans2!=guilt)
            {
                cout<<"Cannot Determine";//有两个人都可能是犯人
                exit(0);
            }
        }
        else if(cnt==2)
        {
            cout<<"Cannot Determine";//有两个人都可能是犯人
            exit(0);
        }
        else if(_cnt==m-1)//这样也可以判断出犯人,因为n-1个人不可能是犯人
        {
            for(int i=1;i<=m;i++)//找到犯人
                if(!vis[i])
                {
                    guilt=i;
                    break;
                }
            if(!ans1) ans1=1,ans2=guilt;
            else if(ans1==1&&ans2!=guilt)//判断与上面相同
            {
                cout<<"Cannot Determine";
                exit(0);
            }
        }
        NoSolution:
        for(int i=1;i<=m;i++)//回退到判断之前
            if(lie[i])
                for(int j=1;j<=m;j++)
                    if(think[i][j]==1) think[i][j]=2;
                    else if(think[i][j]==2) think[i][j]=1;
    }
    

    然后 面向数据编程 就能(AC)了。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    int m,n,p,ans1,ans2;
    string name[25],week[8]={"","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
    int think[25][25];
    bool day[25][7],lie[25],vis[25];
    void judge()
    {
        memset(vis,false,sizeof vis);
        int cnt=0,_cnt=0,guilt=0,true_day=0;
        for(int i=1;i<=m;i++)
            if(lie[i])
                for(int j=1;j<=m;j++)
                    if(think[i][j]==1) think[i][j]=2;
                    else if(think[i][j]==2) think[i][j]=1;
        for(int i=1;i<=m;i++)
        {
            if(lie[i]) continue;
            int hjj=0;
            for(int j=1;j<=7;j++)
                if(day[i][j])
                {
                    if(hjj) goto NoSolution;
                    else hjj=j;
                }
            if(!true_day) true_day=hjj;
            else if(hjj&&hjj!=true_day) goto NoSolution;
        }
        if(true_day)
            for(int i=1;i<=m;i++)
                if(lie[i]&&day[i][true_day]) goto NoSolution;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++)
                if(think[j][i])
                {
                    int state=think[j][i];
                    for(int k=j+1;k<=m;k++) if(think[k][i]&&think[k][i]!=state) goto NoSolution;
                    if(state==1) guilt=i,cnt++;
                    else if(state==2) _cnt++,vis[i]=true;
                    break;
                }
        if(cnt==1)
        {
            if(!ans1) ans1=1,ans2=guilt;
            else if(ans1==1&&ans2!=guilt)
            {
                cout<<"Cannot Determine";
                exit(0);
            }
        }
        else if(cnt==2)
        {
            cout<<"Cannot Determine";
            exit(0);
        }
        else if(_cnt==m-1)
        {
            for(int i=1;i<=m;i++)
                if(!vis[i])
                {
                    guilt=i;
                    break;
                }
            if(!ans1) ans1=1,ans2=guilt;
            else if(ans1==1&&ans2!=guilt)
            {
                cout<<"Cannot Determine";
                exit(0);
            }
        }
        NoSolution:
        for(int i=1;i<=m;i++)
            if(lie[i])
                for(int j=1;j<=m;j++)
                    if(think[i][j]==1) think[i][j]=2;
                    else if(think[i][j]==2) think[i][j]=1;
    }
    void dfs(int now,int tot)
    {
        if(tot==n)
        {
            judge();
            return ;
        }
        if(now>m||m-now+1+tot<n) return ;
        lie[now]=true;
        dfs(now+1,tot+1);
        lie[now]=false;
        dfs(now+1,tot);
    }
    int main()
    {
        cin>>m>>n>>p;
        for(int i=1;i<=m;i++) cin>>name[i];
        getchar();
        getchar();
        while(p--)
        {
            string str;
            getline(cin,str);
            string now;
            int p;
            for(p=0;p<str.length();p++)
                if(str[p]==':') break;
                else now+=str[p];
            int id=0;
            for(int i=1;i<=m;i++)
                if(name[i]==now)
                {
                    id=i;
                    break;
                }
            p+=2;
            now="";
            while(isalpha(str[p])) now+=str[p++];
            p++;
            if(now=="I")
            {
                now="";
                while(isalpha(str[p])) now+=str[p++];
                p++;
                if(now=="am")
                {
                    now="";
                    while(isalpha(str[p])) now+=str[p++];
                    if(now=="guilty"&&str[p]=='.') think[id][id]=1;
                    else if(now=="not")
                    {
                        p++;
                        now="";
                        while(isalpha(str[p])) now+=str[p++];
                        if(now=="guilty"&&str[p]=='.') think[id][id]=2;
                    }
                }
            }
            else if(now=="Today")
            {
                now="";
                while(isalpha(str[p])) now+=str[p++];
                p++;
                if(now=="is")
                {
                    now="";
                    while(isalpha(str[p])) now+=str[p++];
                    p++;
                    for(int i=1;i<=7;i++)
                        if(now==week[i])
                        {
                            day[id][i]=true;
                            break;
                        }
                }
            }
            else
            {
                int to=0;
                for(int i=1;i<=m;i++)
                    if(name[i]==now)
                    {
                        to=i;
                        break;
                    }
                if(to)
                {
                    now="";
                    while(isalpha(str[p])) now+=str[p++];
                    p++;
                    if(now=="is")
                    {
                        now="";
                        while(isalpha(str[p])) now+=str[p++];
                        if(now=="guilty"&&str[p]=='.') think[id][to]=1;
                        else if(now=="not")
                        {
                            p++;
                            now="";
                            while(isalpha(str[p])) now+=str[p++];
                            if(now=="guilty"&&str[p]=='.') think[id][to]=2;
                        }
                    }
                }
            }
        }
        dfs(1,0);
        if(ans1) cout<<name[ans2];
        else
        {
            if(n==m) cout<<"Cannot Determine";
            else cout<<"Impossible";
        }
        return 0;
    }
    
  • 相关阅读:
    为什么要用MarkDown?
    Android Studio: Application Installation Failed
    git查看某个文件修改历史
    有些事现在不做,一辈子都不会做了
    onMouseOver&onMouseOut vs onMouseEnter&onMouseLeave
    versionCode & versionName
    display:none vs visibility:hidden
    polyfill
    combineReducers
    React Context
  • 原文地址:https://www.cnblogs.com/coder-Uranus/p/9904731.html
Copyright © 2020-2023  润新知