转:二分图的必须边

 POJ1486, FOJ1202

在自己做的二分图的题目当中,除了常见的最大匹配、最小覆盖、最大独立集、最小路径覆盖、带权最佳匹配外,自己还发现一类题型,就是要求出二分图里的哪些边是能够确定的。因为自己没系统的学习过二分图,我暂时把这些边叫做二分图的必须边。这些题的一般是给出哪些边可能存在或一定不存在,要你通过计算输出这样的二分图中哪些边是一定存在的。

|

|

 

 

先看一个例子:POJ1486

       这道题的意思是一些大小不等透明的幻灯片(只有轮廓和上面的数字可见)ABCDE…按顺序叠放在一起,现在知道每个幻灯片左上角和右下角的坐标,并且由于幻灯片是透明的,所以能看到幻灯片上的数字(给出了每个数字的坐标,但不知道这些数字分别属于哪个幻灯片),现在要你根据当前的已知信息,输出能够确定的幻灯片编号和数字的匹配,例如(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");

|

你可能感兴趣的:(编程,c,算法,测试,任务)