John先生晚上写了n封信,并相应地写了n个信封将信装好,准备寄出。但是,第二天John的儿子Small John将这n封信都拿出了信封。不幸的是,Small John无法将拿出的信正确地装回信封中了。
将Small John所提供的n封信依次编号为1,2,…,n;且n个信封也依次编号为1,2,…,n。假定Small John能提供一组信息:第i封信肯定不是装在信封j中。请编程帮助Small John,尽可能多地将信正确地装回信封。
输入描述 Input Description
n文件的第一行是一个整数n(n≤100)。信和信封依次编号为1,2,…,n。
n接下来的各行中每行有2个数i和j,表示第i封信肯定不是装在第j个信封中。文件最后一行是2个0,表示结束。
输出描述 Output Description
输出文件的各行中每行有2个数i和j,表示第i封信肯定是装在第j个信封中。请按信的编号i从小到大顺序输出。若不能确定正确装入信封的任何信件,则输出“none”。
样例输入 Sample Input
3
1 2
1 3
2 1
0 0
样例输出 Sample Output
1 1
一、正确的匹配一定是一种完美匹配,(每封信都有一个信封可以装),所以不是完美匹配可以直接输出none进行剪枝。
二、如果存在一封信确定装在某个信封中,那么任何一种完美一定包含这个关系(因为关系唯一,所以为了达到完美匹配,必定会包含这个关系)。
通过一次匹配,找出所有的关系。当然,现在还不知道哪些边是确定的答案。接着测试每一条边,通过删除一条边并重新DFS搜索,如果找不到其它可匹配的,那么此条边一定是确定的(因为关系唯一)
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include<iostream>
#include<algorithm>
using namespace std ;
#define N 105
bool map[N][N],used[N];
int n,pre[N],pre1[N];
struct node
{
int x,y;
};
bool cmp(node a,node b)
{
return a.x<b.x;
}
int dfs(int u)
{
int i;
for(i=1;i<=n;i++)
if(!used[i]&&map[u][i])
{
used[i]=1;
if(pre[i]==-1||dfs(pre[i]))
{
pre[i]=u;
return 1;
}
}
return 0;
}
int dfs1(int u)
{
int i;
for(i=1;i<=n;i++)
if(!used[i]&&map[u][i])
{
used[i]=1;
if(pre1[i]==-1||dfs1(pre1[i]))
{
pre1[i]=u;
return 1;
}
}
return 0;
}
int main()
{
while(cin>>n)
{
int a,b,i,j;
memset(map,1,sizeof(map));
while(scanf("%d%d",&a,&b),a&&b)
map[a][b]=0;
memset(pre,-1,sizeof(pre));
int ans=0;
for(i=1;i<=n;i++)
{
memset(used,false,sizeof(used));
if(dfs(i))
ans++;
}
if(ans!=n)
{
cout<<"none"<<endl<<endl;
continue;
}
node edge[N];
int cnt=0;
for(i=1;i<=n;i++)
{
map[pre[i]][i]=0;
ans=0;
memset(pre1,-1,sizeof(pre1));
for(j=1;j<=n;j++)
{
memset(used,false,sizeof(used));
if(dfs1(j))
ans++;
}
if(ans!=n)
{
edge[cnt].x=pre[i];
edge[cnt++].y=i;
}
map[pre[i]][i]=1;
}
sort(edge,edge+cnt,cmp);
if(cnt==0)
{
cout<<"none"<<endl<<endl;
continue;
}
for(i=0;i<cnt;i++)
printf("%d %d\n",edge[i].x,edge[i].y);
cout<<endl;
}
return 0;
}