POJ1486, FOJ1202
在自己做的二分图的题目当中,除了常见的最大匹配、最小覆盖、最大独立集、最小路径覆盖、带权最佳匹配外,自己还发现一类题型,就是要求出二分图里的哪些边是能够确定的。因为自己没系统的学习过二分图,我暂时把这些边叫做二分图的必须边。这些题的一般是给出哪些边可能存在或一定不存在,要你通过计算输出这样的二分图中哪些边是一定存在的。
|
|
先看一个例子:POJ1486
这道题的意思是一些大小不等透明的幻灯片(只有轮廓和上面的数字可见)A、B、C、D、E…按顺序叠放在一起,现在知道每个幻灯片左上角和右下角的坐标,并且由于幻灯片是透明的,所以能看到幻灯片上的数字(给出了每个数字的坐标,但不知道这些数字分别属于哪个幻灯片),现在要你根据当前的已知信息,输出能够确定的幻灯片编号和数字的匹配,例如(A,4) (B,1) (C,2) (D,3).
解这道题的思路是:先根据已知信息建立二分图,通过坐标计算把可能存在的边赋值为1,然后用匈牙利算法进行最大匹配,当前则得到了一个最大匹配,然后每次删除一条边,对该边的一个顶点进行再次匹配,如果匹配成功则不是必须边,只有匹配不成功才是必须边。
核心代码大致如下:
MaxMatch(); //进行最大匹配
yes = 0;
for(i = 1; i <= n; i++) //验证match[i]与i是不是唯一匹配的
{
x = match[i]; match[i] = -1;
g[x][i] = 0;
memset(flag, 0, sizeof(flag));
if(!dfs(x))//如果dfs(x)==0即找不到,就表示是唯一匹配,即可输出!
{
match[i] = x;
yes++;
if(yes > 1) printf(" ");
printf("(%c,%d)", 'A'+i-1, match[i]); //输出字母和字母对应的数字
}
g[x][i] = 1;
}
if(!yes) printf("none");
|
|
再看一个例子:FOJ1202 信与信封问题
题目描述如下:
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,尽可能多地将信正确地装回信封。
这道题如上面一道题类似,下面是我的分析:
-、正确的匹配一定是一种完美匹配,(每封信都有一个信封可以装),所以不是完美匹配可以直接输出none进行剪枝。
二、如果存在一封信确定装在某个信封中,那么任何一种完美一定包含这个关系(因为关系唯一,所以为了达到完美匹配,必定会包含这个关系)。
通过一次匹配,找出所有的关系。当然,现在还不知道哪些边是确定的答案。接着测试每一条边,通过删除一条边并重新DFS搜索,如果找不到其它可匹配的,那么此条边一定是确定的(因为关系唯一)。核心代码如下:
//MaxMatch(); //0.05 s
if(MaxMatch()<u) {printf("none/n/n"); continue;} //0.01 s, 进行判断和剪枝
yes = 0;
for(i = 1; i <= u; i++)
{
x = match[i]; match[i] = -1;
g[x][i] = 0;
memset(flag, 0, sizeof(flag));
if(!dfs(x))
{
match[i] = x;
yes++;
printf("%d %d/n", i, match[i]);
}
g[x][i] = 1;
}
if(!yes) printf("none/n");
|