POJ 1043 What's In A Name? 二分图推理

题意:有n(1<=n<=20)个人,每一个人在发电报的时候是以固定的绰号发送的,现在给定一串序列表示某个人进入房间,某个人从房间出去,或者截获了以

         什么绰号发送的电报,问能否推出每个人对应的绰号是什么,如果推理不出来输出"???"。

题解:很容易想到二分匹配,但是正常思维构图之后会发现很难搞,因为一些明明矛盾的边的关系也搞进去了,类似于建反图的方法,每次把一定不会满足条件

         的边去掉,最后剩下的边是可能满足的关系对,之后枚举每一个二分图中的必须边,如果删除后匹配数减少那么当前的匹配是正确的否则是不确定的。


Sure原创,转载请注明出处。

#include <iostream>
#include <cstdio>
#include <string>
#include <memory.h>
#include <map>
#include <utility>
#include <algorithm>
using namespace std;
const int maxn = 22;
struct ANS
{
    string sp,real;
    bool operator < (const ANS &other) const
    {
        return sp < other.sp;
    }
}res[maxn];
string name[maxn];
int match[maxn],who[maxn],save[maxn];
bool vis[maxn],relation[maxn][maxn],in[maxn];
map <string , int> hash , room , spy;
int m,n,top;

void init()
{
    hash.clear();
    room.clear();
    spy.clear();
    top = m = 0;
    memset(who,-1,sizeof(who));
    memset(relation,true,sizeof(relation));
    return;
}

void read()
{
    for(int i=1;i<=n;i++)
    {
        cin >> name[i];
        hash[name[i]] = i;
    }
    return;
}

void make()
{
    char str[3];
    string ss;
    while(scanf("%s",str) && str[0] != 'Q')
    {
        cin >> ss;
        if(str[0] == 'E')
        {
            int tmp = spy[ss];
            if(tmp == 0)
            {
                spy[ss] = ++m;
                tmp = m;
            }
            room[ss] = tmp;
        }
        else if(str[0] == 'L') room.erase(ss);
        else
        {
            memset(in,false,sizeof(in));
            int v = hash[ss];
            map <string , int>::iterator it;
            for(it = room.begin();it != room.end();it++)
            {
                in[(*it).second] = true;
            }
            for(int i=1;i<=n;i++)
            {
                if(in[i] == false) relation[i][v] = false;
            }
        }
    }
    return;
}

bool find(int u)
{
    for(int i=1;i<=n;i++)
    {
        if(relation[u][i] && vis[i] == false)
        {
            vis[i] = true;
            if(match[i] == -1 || find(match[i]))
            {
                who[u] = i;
                match[i] = u;
                return true;
            }
        }
    }
    return false;
}

int hungary()
{
    int cnt = 0;
    memset(match,-1,sizeof(match));
    for(int i=1;i<=m;i++)
    {
        memset(vis,false,sizeof(vis));
        if(find(i)) cnt++;
    }
    return cnt;
}

void solve()
{
    int tot = hungary();
    for(int i=1;i<=m;i++)
    {
        save[i] = who[i];
    }
    map <string , int>::iterator it;
    for(it = spy.begin();it != spy.end();it++)
    {
        int u = (*it).second;
        res[top].sp = (*it).first;
        if(save[u] == -1)
        {
            res[top++].real = "???";
            continue;
        }
        relation[u][save[u]] = false;
        if(hungary() < tot) res[top++].real = name[save[u]];
        else res[top++].real = "???";
        relation[u][save[u]] = true;
    }
    sort(res , res + top);
    for(int i=0;i<top;i++)
    {
        cout<<res[i].sp<<":"<<res[i].real<<endl;
    }
    return;
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        read();
        make();
        solve();
    }
    return 0;
}

你可能感兴趣的:(POJ 1043 What's In A Name? 二分图推理)