zoukankan      html  css  js  c++  java
  • 洛谷 P1039侦探推理

    /*
    枚举罪犯和星期几,那么所有人说的话是真是假一目了然。
    首先一个人不能既说真话又说假话。
    即:
    I am guilty.
    I am not guilty.
    因为非真即假,所以直接判断impossible.
    map<string,int>表示名字对应的id  name[i]表示id为i的人对应的人名。 
    kp[i][j]表示第i个人认为第j个人是不是罪犯。0/-1/1,表示不是,没说,是 
    kd[i][j]表示第i个人认为今天是星期j么?0/-1/1表示 不认为、没说、认为 
    impossible的情况之一即kp[i][j]=1后又要赋值为 kp[i][j]=0;
    
    
    假设罪犯是t(id),今天是d;//现在已经没有人既说真话又说假话了。
    
    现在人有三类:
    说真话 说假话 说废话 
    如何判断一个人说真话还是说假话。
    假设
    Amy: 
    ①I am guilty. (如果Amy不是t,那么这人说假话;如果Amy是t,那么这个人一定说真话)
    ②I am not guilty. (如果他是t,那么这人说假话;如果不是t,那么它一定说真话) 
    ③XXX is guilty. (XXX是t,真话;XXX不是t,假话)
    ④XXX is not guilty. (XXX是t,假话;XXX不是t,真话) 
    ⑤Today is x  (x是d,真话;x不是d,假话)。
    
    所以,一个人只要不说废话,那么他说真话还是说假话都知道了 
    say[i]=0/-1/1表示id为i的人说假话,不确定,说真话 
    
    若一个人说的是假话,那么他说的假话的反面就是真话。 
    下面的句子是可以通过这个人说的是假话判断出来的。 
    ①他不是罪犯 
    ②他是罪犯
    ③XXX 不是罪犯
    ④XXX 是罪犯 
    这时需要另辟数组来标记。
    p[i]=0/-1/1分别表示这个人不是罪犯、不确定、是罪犯。
    d[i]=0/-1/1分别表示今天不是星期i、不确定是不是星期i、今天是星期i。
    
    这时矛盾出现了
    
    甲:
    A is guilty.
    t is not guilty.
    乙:
    A is not guilty.
    t is not guilty.
    
    此时甲、乙二人都不认为t是罪犯,那么他们说的都是假话了
    根据甲来说:A 应该不是罪犯。
    根据乙来说:A 应该是罪犯。
    出现了矛盾,这个情况应该pass了。
    即p[i]赋值为0后,又要被赋值为1。d数组同样。
    所以p[]、d[]数组只能从不确定状态赋值为确定状态,不能从一个
    确定状态标记为另一个确定状态。
    
    如果说谎话的人<=n&&说谎的人+说废话的人>=n,那么满足始终有n个人说假话了。
    
    在看p[i]数组,如果有人标记了不确定是不是罪犯,那么这个情况就是不确定罪犯了。
    
    所以最后
    1)若唯一能确定罪犯,输出。
    2)不能唯一确定,有多解的情况 cannot determine。
    3)所有举例的情况都有矛盾,都被pass了,impossible.

    下面的代码windows下是A的...洛谷A不了....占个坑。

    #include<iostream>
    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    
    int m,n,p,ans;
    
    int say[22];
    
    int kp[22][22],kd[22][10]; 
    
    string name[22];
    
    string a[22],b[22],c[22];
    
    map<string,int>k;
    
    void read()
    {
        for(int i=1;i<=m;i++)
        {
            string s;
            cin>>s; name[i]=s;
            s+=":"; k[s]=i;
        }
    //    char ch=getchar();
       // while(ch==10)ch=getchar();getchar();
        for(int i=1;i<=p;i++)
        {
            cin>>a[i]>>b[i];
            if(b[i]!="Today"&&c[i]!=" is guilty."&&c[i]!=" is not guilty.")b[i]+=":";//***
            getline(cin,c[i]);
        }
    }
    
    void pre_deal()
    {
        int flag=0;
        memset(kp,-1,sizeof(kp));
        memset(kd,-1,sizeof(kd));
        for(int i=1;i<=p;i++)
        {
            int id=k[a[i]];
            if(c[i]==" am guilty.") {if(!kp[id][id]) flag=1;else kp[id][id]=1;}
            if(c[i]==" am not guilty."){if(kp[id][id]==1) flag=1;else kp[id][id]=0;}
            if(c[i]==" is guilty.") {int h=k[b[i]];if(!kp[id][h]) flag=1;else kp[id][h]=1;}
            if(c[i]==" is not guilty."){int h=k[b[i]];if(kp[id][h]==1) flag=1;else kp[id][h]=0;}
            if(b[i]=="Today")
            {
                if(c[i]==" is Monday.") kd[id][1]=1;
                if(c[i]==" is Tuesday.") kd[id][2]=1;
                if(c[i]==" is Wednesday.") kd[id][3]=1;
                if(c[i]==" is Thursday.") kd[id][4]=1;
                if(c[i]==" is Friday.") kd[id][5]=1;
                if(c[i]==" is Saturday.") kd[id][6]=1;
                if(c[i]==" is Sunday.") kd[id][7]=1;
            }
            if(flag){printf("Impossible
    ");exit(0);}  //***
        }
    }
    
    bool check(int x,int y)
    {
        memset(say,-1,sizeof(say));
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if((kp[i][j]==1&&j!=x)||(kp[i][j]==0&&j==x))
                {
                    if(say[i]==1) return false; 
                    say[i]=0; 
                }
                if((kp[i][j]==1&&j==x)||(kp[i][j]==0&&j!=x))
                {
                    if(say[i]==0) return false;
                    say[i]=true; 
                }
            }
            for(int q=1;q<=7;q++)
            {
                if(kd[i][q]==1&&q!=y)
                {
                    if(say[i]==1) return false;
                    say[i]=0;
                }
                if(kd[i][q]==1&&q==y)
                {
                    if(say[i]==0) return false;
                    say[i]=true;
                }
            } 
        }
        return true;
    }
    
    int main()
    {
        scanf("%d%d%d",&m,&n,&p);//m同学数,n始终说谎的人数,p为证言总数。
        read(); 
        pre_deal();
        for(int i=1;i<=m;i++)
        {
            for(int j=1;j<=7;j++)
            {
                int saylie=0,notjudge=0;
                if(check(i,j))
                {
                    for(int p=1;p<=m;p++)
                    {
                        if(say[p]==-1) notjudge++;
                        if(say[p]==0) saylie++;
                    }
                    if(saylie<=n&&notjudge+saylie>=n)
                    {
                        if(ans&&i!=ans)
                        {
                            printf("Cannot Determine
    ");
                            exit(0);
                        }
                        ans=i;
                    }
                }
            }
        }
        if(ans) cout<<name[ans]<<endl;
        else printf("Impossible
    ");
        return 0;
    }
  • 相关阅读:
    linux中apt-get使用
    部署ceph
    cinder存储服务
    ceph简介
    Horizon Web管理界面
    neutron网络服务2
    neutron网络服务
    nova计算服务
    cinder存储服务
    keystone身份认证服务
  • 原文地址:https://www.cnblogs.com/zzyh/p/9539107.html
Copyright © 2011-2022 走看看