题目描述 Description
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,尽可能多地将信正确地装回信封。
n文件的第一行是一个整数n(n≤100)。信和信封依次编号为1,2,…,n。
n接下来的各行中每行有2个数i和j,表示第i封信肯定不是装在第j个信封中。文件最后一行是2个0,表示结束。
输出描述 Output Description
输出文件的各行中每行有2个数i和j,表示第i封信肯定是装在第j个信封中。请按信的编号i从小到大顺序输出。若不能确定正确装入信封的任何信件,则输出“none”。
3
1 2
1 3
2 1
0 0
样例输出 Sample Output
1 1
思路:
先跑匈牙利算法,判断是否能全部匹配
如果不能匹配 那么直接输出“none”
如果能匹配起来 那么再检验 哪个一定匹配正确
可以删边来判断 删去一个匹配好的边
看看是否能全部匹配
代码:
#include<cstdio>
#include<iostream>
#define MAXN 110
using namespace std;
int f[MAXN][MAXN],n,pre[MAXN],pre2[MAXN];
bool vis[MAXN],flag;
inline void read(int&x) {
int f=1;x=0;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') x=10*x+c-48,c=getchar();
x=x*f;
}
inline int find(int u) {
for(int i=1;i<=n;i++) {
if(!f[u][i]&&!vis[i]) {
vis[i]=true;
if(!pre[i]||find(pre[i])) {
pre[i]=u;
return 1;
}
}
}
return 0;
}
inline void check() {
for(int i=1;i<=n;i++) pre2[pre[i]]=i;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) vis[j]=false;
f[i][pre2[i]]=1;
pre[pre2[i]]=0;
if(!find(i)) {
printf("%d %d\n",i,pre2[i]);
flag=true;
}
pre[pre2[i]]=i;
f[i][pre2[i]]=0;
}
}
int main() {
int x,y;
read(n);
while(true) {
read(x);read(y);
if(!x&&!y) break;
f[x][y]=true;
}
int ans=0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) vis[j]=false;
ans+=find(i);
}
if(ans!=n) {
printf("none\n");
return 0;
}
check();
if(!flag) printf("none\n");
return 0;
}