您的位置:首页 > 其它

poj 1043 What's In A Name 二分匹配

2012-12-02 11:43 435 查看
题意:

有n(1<=n<=20)个人,每一个人在发电报的时候是以固定的绰号发送的,现在给定一串序列表示某个人进入房间,某个人从房间出去,或者截获了以什么绰号发送的电报,问能否推出每个人对应的绰号是什么,如果推理不出来输出"???"。

解题思路:

如果删除某边后最大匹配数变小,这条边便是唯一匹配方案,是所要的答案

View Code

#include<cstdio>            // poj 1043  What's In A Name?
#include<iostream>            // 224K    47MS    C++
#include<cstring>
#include<string>
#include<algorithm>
#include<map>                // 该题字符串的处理很多,用了 map 和 set 来存储数据
#include<set>
using namespace std;

const int MAXN = 30;
int T, cas;
int n;
string real[MAXN], reco[MAXN];    // 用户名和代号
string sign, name;                // 输入所用的变量
map< string, int >mp1;            // 用来保存用户名
map< string, int >mp2;            // 用来记录代号
bool g[MAXN][MAXN], vis[MAXN];    // 17-18 匈牙利算法所用的变量
int cx[MAXN], cy[MAXN], nx, ny;
set< int >cur;                    // set 的插入与消去,好好用,第一次实用
pair< string, int >pair1[MAXN];    // 20-21 解的保存,pair的第一次实用
int os[MAXN];
/**************** 1-3 函数是算法模板 **********************/
void init()
{
memset( g, true, sizeof(g) );
}

int dfs( int u )
{
int v;
for( v = 1; v <= ny; v++ )
{
if( g[u][v] && !vis[v] )
{
vis[v] = true;
if( !cy[v] || dfs( cy[v] ) )
{
cx[u] = v;
cy[v] = u;
return 1;
}
}
}
return 0;
}

int MaxMatch()
{
int u, ret;
memset( cx, 0, sizeof(cx) );
memset( cy, 0, sizeof(cy) );
ret = 0;
for( u = 1; u <= nx; u++ )
{
if( !cx[u] )
{
memset( vis, false, sizeof(vis) );
ret += dfs( u );
}
}
return ret;
}
/************ 数据的读入 ***************/
void readcase()
{
int i;
scanf( "%d", &n );
for( i = 1; i <= n; i++ )
{
cin>>real[i];
mp1[real[i]] = i;
}
int cnt;
cnt = 0;
while( cin>>sign, sign != "Q" )
{
cin>>name;
if( sign == "E" )
{
if( mp2[name] == 0 )
{
mp2[name] = ++cnt;
reco[cnt] = name;
}
int y = mp2[name];
cur.insert( y );    // set 的插入
}
else if( sign == "L" )
{
int y = mp2[name];
cur.erase( y );        // set 的消去元素
}
else
{
int x = mp1[name];
for( i = 1; i <= n; i++ )if( cur.find( i ) == cur.end() )
g[x][i] = false;    // 去掉没有关系的边
}
}
nx = ny = n;                // 待验证??????????????????????
}

void deal( int mat )            // 枚举去掉存在的边,在求最大匹配,如减少,则该边存在
{
int i, j, tmp;
for( i = 1; i <= n; i++ )
{
pair1[i] = make_pair( reco[i], i );
os[i] = 0;
for( j = 1; j <= n; j++ )
{
if( g[j][i] )
{
g[j][i] = false;
tmp = MaxMatch();
if( tmp != mat )
{
os[i] = j;
}
g[j][i] = true;
}
}
}
sort( pair1 + 1, pair1 + n +1 );    // 对解的排序
}

void print()
{
int i, j;
for( i = 1; i <= n; i++ )
{
cout<< pair1[i].first << ":";
if( os[pair1[i].second] == 0 )
cout<< "???" << endl;
else
cout<< real[os[pair1[i].second]] << endl;
}
}
int main()
{
init();
readcase();
int mat;
mat = MaxMatch();
deal( mat );
print();
return 0;
}


这个是八数码问题??

不清楚吧,当二分图来练习了。

用STL来A题,这是头一次,map,set,感觉功能好犀利。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: