P1039 [NOIP2003 提高组] 侦探推理

发布于:2024-04-24 ⋅ 阅读:(27) ⋅ 点赞:(0)

注意换行符!!!

如果你使用getchar()系列函数读入,并且用换行符判定是否结束,则换行符会导致你WA掉!

linux下换行符为’\n’,windows下换行符为’\r\n’,如果数据是windows下造的,你就把’\r’也给当成字符串内容了,不wa才怪。

所以,你可以选择建立一个缓存区,把所有的’\r’替换成’\n’,进行计算。

读取一整行的方法:

fgets(char* dst,size_t buf_size,File* file)
最后一个参数传stdin即可。不要用scanf(“%[^\n]”,str),因为你不知道最后的换行符是啥!

另外为了预防文末没换行的情况,手动在缓存区末补上一个’\n’。

具体算法不多说了,先预处理出每个人表示的意思,然后二进制状压枚举撒谎的人,如果这个状态的大小与所给人数相同,则进行计算。记得判定矛盾。可能这个状态是互相矛盾的,则不应更新答案。

如果输入存在矛盾,直接输出impossible。

如果一个状态有多个人未知,且没有人必定为罪犯则多解。

如果多个状态推出不同的罪犯,则多解。

如果一个状态只有一个人未知,其余的人都一定不是罪犯,则用这个不确定的人是罪犯去更新答案。

最后数一下有多少个人可能是罪犯,统计size,如果size为0则输出impossible,为1则输出人名,其余情况输出多解。
最后上代码:

#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;
}