「NOIP2003」侦探推理

题目描述

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

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

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

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

输入格式

输入由若干行组成,第一行有二个整数,M(1≤M≤20)、N(1≤N≤M)和P(1≤P≤100);

M是参加游戏的明明的同学数,N是其中始终说谎的人数,P是证言的总数。接下来M行,

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

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

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

输出格式

如果你的程序能确定谁是罪犯,则输出他的名字;如果程序判断出不止一个人可能是

罪犯,则输出 Cannot Determine;如果程序判断出没有人可能成为罪犯,则输出 Impossible。


AC代码又来了~:

#include<bits/stdc++.h>
#define debug cout
using namespace std;
const int maxn=30;
string name[maxn];
int ptr[maxn][maxn]; // 1 means is , -1 means not;
int day[maxn]; // means says day.
int day_can_be[maxn]; // can be that day ? 1 means is , -1 means is not.
int gul_can_be[maxn]; // persob i can be guilty or not , 1 means is , -1 means is not;
int may_be_ans[maxn]; // 0,1 means can be answer or not
string buf[1<<10];
map<string,int> person;
int n,m,p,mx,cnt,ans;
inline int getdate(string x)
{
    if(x=="monday.") return 1;
    if(x=="tuesday.") return 2;
    if(x=="wednesday.") return 3;
    if(x=="thursday.") return 4;
    if(x=="friday.") return 5;
    if(x=="saturday.") return 6;
    if(x=="sunday.") return 7;
    return puts("Wrong spelling ! Fuck you!"),-1;
}
inline char convchar(char x)
{
    if( x>='A' && x<='Z' )
        return x-'A'+'a';
    else return x;
}
inline void convstring(string &x)
{
    for(unsigned i=0;i<x.length();i++)
        x[i] = convchar(x[i]);
}
inline char nextchar(int arg=0)
{
    static char buf[1<<10],*st;
    if(arg)
    {
        fgets(buf,1<<10,stdin),st=buf;
        int i;
        for(i=0;i<1<<10&&buf[i];i++)
            if( buf[i]=='\r' )
                buf[i] = '\n';
        buf[i] = '\n';
    }
    return *st++;
}
inline void getline()
{
    cnt = 0;
    char c=nextchar(1);
    cnt = 1;
    while( c != '\n' )
    {
        if(c==' ')
        {
            if( person.find(buf[cnt]) == person.end() )
                convstring(buf[cnt]);
            cnt++;
        }
        else
            buf[cnt] = buf[cnt] + c;
        c = nextchar();
    }
    while( buf[cnt]=="" ) cnt--;
    convstring(buf[cnt]);
}
inline void resbuf()
{
    for(int i=1;i<=cnt;i++)
        buf[i].clear(),
        buf[i].resize(0);
}
inline void explain()
{
    if( buf[2]!="i" && buf[2]!="today" && person.find(buf[2])==person.end() ) return;
    const int id = person[buf[1]];
    if( buf[2]=="today" )
    {
        int dd = getdate(buf[4]);
        if( day[id] && day[id]!=dd )
        {
            ans = -2;
            return;
        }
        day[id] = dd;
    }
    else if( buf[4]=="guilty." )
    {
        int tar = buf[2]=="i" ? id : person[buf[2]];
        if( ptr[id][tar] && ptr[id][tar]!=1 )
        {
            ans = -2;
            return;
        }
        ptr[id][tar] = 1;
    }
    else if( buf[5]=="guilty." )
    {
        int tar = buf[2]=="i" ? id : person[buf[2]];
        if( ptr[id][tar] && ptr[id][tar]!=-1 )
        {
            ans = -2;
            return;
        }
        ptr[id][tar] = -1;
    }
}
inline void reslogic()
{
    memset(day_can_be,0,sizeof(day_can_be));
    memset(gul_can_be,0,sizeof(gul_can_be));
}
inline void logic(int x,int mul,int& flag)
{
    if(day[x])
    {
        if( day_can_be[day[x]] && day_can_be[day[x]]!=mul )
        {
            flag=0;
            return;
        }
        day_can_be[day[x]] = mul;
    }
    for(int i=1;i<=n;i++)
        if(ptr[x][i])
        {
            const int pp = ptr[x][i]*mul;
            if( gul_can_be[i] && gul_can_be[i]!=pp )
            {
                flag = 0;
                return;
            }
            gul_can_be[i] = pp;
        }
}
inline bool judgedate()
{
    int ret=0;
    for(int i=1;i<=7;i++)
        if( ~day_can_be[i] )
            ret += day_can_be[i];
    return ret<2;
}
inline void judgegul()
{
    int pos = -1,siz=n;
    for(int i=1;i<=n;i++)
    {
        if( !~gul_can_be[i] ) --siz;
        else if( gul_can_be[i] == 1 )
        {
            pos = i;
            break;
        }
    }
    if( siz>1 && !~pos ) // can not determine , maybe multi guilty .
    {
        ans = -1;
        return;
    }
    if( siz==1 && !~pos )
        for(int i=1;i<=n;i++)
            if( !gul_can_be[i] )
            {
                may_be_ans[i] = 1;
                return;
            }
    for(int i=1;i<=n;i++)
        if( i!=pos && gul_can_be[i] == 1 ) // must be multi guilty in this statement
            return;
    may_be_ans[pos] = 1;
}
inline int count(int x)
{
    int ret=0;
    while(x)
        ret++,
        x -= (x&-x);
    return ret;
}
inline int getans()
{
    int ret = 0;
    for(int i=1;i<=n;i++)
        if( may_be_ans[i] )
        ret++,
        ans = i;
    return ret;
}
int main()
{
    scanf("%d%d%d",&n,&m,&p);
    mx = (1<<n);
    for(int i=1;i<=n;i++)
    {
        cin>>name[i];
        person[name[i]] = person[name[i]+":"] = i;
    }
    char c = nextchar(1);
    while(c!='\n') c=nextchar();
    for(int i=1;i<=p;i++)
    {
        resbuf();
        getline();
        explain();
    }
    if( ans == -2 )
        return puts("Impossible"),0;
    for(int s=0;s<mx;s++)
    {
        if( count(s) != m ) continue;
        reslogic();
        int flag =1;
        for(int i=1;i<=n&&flag;i++)
            if( s & (1<<(i-1)) )
                logic(i,-1,flag);
            else logic(i,1,flag);
        if( flag && judgedate() )
            judgegul();
    }
    if( !~ans )
        return puts("Cannot Determine"),0;
    if( !getans() )
        return puts("Impossible"),0;
    if( getans() > 1 )
        return puts("Cannot Determine"),0;
    cout<<name[ans]<<endl;
    return 0;
}

创作不易,点点赞呗~


bye~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值