首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

完美匹配有关问题

2012-09-22 
完美匹配问题Problem DescriptionJohn先生晚上写了n封信,并相应地写了n个信封将信装好,准备寄出。但是,第二

完美匹配问题
Problem 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,尽可能多地将信正确地装回信封。
 Input

本题有多组输入数据,你必须处理到EOF为止。
每组数据的第一行是一个整数n(n≤100)。信和信封依次编号为1,2,…,n。
接下来的各行中每行有2个数i和j,表示第i封信肯定不是装在第j个信封中。输入最后一行是2个0,表示结束。
 Output

对于每组数据,输出的各行中每行有2个数i和j,表示第i封信肯定是装在第j个信封中。请按信的编号i从小到大顺序输出。若不能确定正确装入信封的任何信件,则输出“none”。
每组输出结束之后,输出一个空行。

C/C++ code
#include<iostream>#include<cstdio>#include<cstdlib>#include<memory.h>using namespace std;int v[101], n;int map[101][101];int l[101], f[101];bool find(int x){    for(int i=1;i<=n;++i){        if(!map[x][i] && !v[i]){            v[i] = 1;            if(l[i]==0 || find(l[i])){                l[i] = x;                return true;            }        }    }    return false;}int hungary(){    memset(l, 0, sizeof(l));    int ans = 0;    for(int i=1;i<=n;++i){        memset(v, 0, sizeof(v));        if(find(i))            ans++;    }    return ans;}int main(){    freopen("in.txt", "r", stdin);    freopen("out.txt", "w", stdout);    int s1,s2;    while(cin>>n){        memset(map, 0, sizeof(map));        while(cin>>s1>>s2, s1+s2)            map[s1][s2] = 1;        int should = hungary();        if(should!=n){            cout<<"none"<<endl;            continue;        }        bool flag = false;        memcpy(f, l, sizeof(l));        for(int i=1;i<=n;++i){            map[f[i]][i] = 1;            if(hungary()!=should){                cout<<f[i]<<" "<<i<<endl;                flag = true;            }            map[f[i]][i] = 0;        }        if(!flag)            cout<<"none"<<endl;    }    fclose(stdin);    fclose(stdout);}

请问这代码哪里有错误?一直WA

[解决办法]
我也找了一个反例,但刚才只能回复3次,没办法继续发了。更改了一下这个答案:

http://www.51nod.com/question/index.html#!questionId=539

OOXXX
OOXXX
XOOXX
XXOOO
XXXOO

X表示不能放,O表示可以放。在这个例子里面,第三封信对应第三个信封是可以确定的,却没有一行或一列计数可以达到n-1。

所以:还是使用二分图最大匹配来做,思路还比较简单,就是先求出一个最大匹配(肯定可以匹配n个)对应的边。然后逐个删掉这些边,看最大匹配有没有变化,如果没有变换则说明关系不能确定,如果有变化,那么就说明这条边所对应的关系是惟一的,说明关系是确定的。

不过编程细节及效率优化还有不少复杂的地方,但大体思路就是这样。


探讨

引用:

http://www.51nod.com/question/index.html#!questionId=539

可以看看这个帖子的答案。
他那种做法是错的。我一开始就是用他那种做法,不是只有n-1个信封被排除才能找到解。

……

[解决办法]
cout<<f[i]<<" "<<i<<endl;

你这句能按信的编号从小到大顺序输出?

热点排行