Poj 1486 Sorting Slides + FOJ1202 信与信封问题 (二分图的必须边)
2013-08-03 11:17
459 查看
2015-4-27更新:由于百度空间即将关闭,故将提到的参考文章复制到了最下面。
理论:http://hi.baidu.com/wrpnjmkfhgbimpq/item/e8402237ef272afbdf222100
步骤:
1:求最大匹配,匹配边集合E
2:删除E中的一条边e,以e的一个端点找增广路,若不能找到增广路则e是必须边
3:恢复原图以及E,继续步骤2,直到E中的每条边都被删除过
Poj 1486 Sorting Slides
题意:一些重叠在一起的图片,给你这些图片的四个坐标,给出一些写在图片上的数字的坐标,找到一个匹配使得每一个数字都可以唯一对应于一张图片
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");
|
|
解决这类题当然还有别的方法,但上述方法应该是一个不错的方法,在速度上POJ1486跑了0ms(这个题大家都0ms,看不出算法的优劣),FOJ1202我的代码只用0.01s就跑完了,暂列status里的第一,所以上述算法应该还行。
理论:http://hi.baidu.com/wrpnjmkfhgbimpq/item/e8402237ef272afbdf222100
步骤:
1:求最大匹配,匹配边集合E
2:删除E中的一条边e,以e的一个端点找增广路,若不能找到增广路则e是必须边
3:恢复原图以及E,继续步骤2,直到E中的每条边都被删除过
Poj 1486 Sorting Slides
题意:一些重叠在一起的图片,给你这些图片的四个坐标,给出一些写在图片上的数字的坐标,找到一个匹配使得每一个数字都可以唯一对应于一张图片
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> using namespace std; const int N=40; bool map ; bool vis ; int match ; int n; bool Dfs (int u) { for (int v=1;v<=n;v++) if (vis[v] == false && map[u][v]) { vis[v]=true; if (match[v]==0 || Dfs(match[v])) { match[v]=u; return true; } } return false; } struct Rectangle { int xmin,xmax,ymin,ymax; void Get () { scanf("%d%d%d%d",&xmin,&xmax,&ymin,&ymax); } }r ; struct Point { int x,y; void Get () { scanf("%d%d",&x,&y); } }p ; bool Judge (Rectangle a,Point b) { if (b.x>=a.xmin && b.x<=a.xmax && b.y>=a.ymin && b.y<=a.ymax) return true; return false; } void Deal () { int i,sum=0,flag=0; for (i=1;i<=n;i++) { memset(vis,false,sizeof(vis)); if (Dfs(i)) sum++; } if (sum==n) { for (i=1;i<=n;i++) { int u=match[i]; if (u==0) continue; match[i]=0; map[u][i]=false; memset(vis,false,sizeof(vis)); if (Dfs(u)==false) { flag++; match[i]=u; if (flag>1) printf(" "); printf("(%c,%d)",i-1+'A',match[i]); } map[u][i]=true; } } if (flag==0) printf("none"); printf("\n"); } int main () { #ifdef ONLINE_JUDGE #else freopen("read.txt","r",stdin); #endif int Cas=1; while (~scanf("%d",&n),n) { if (Cas!=1) printf("\n"); printf("Heap %d\n",Cas++); memset(map,false,sizeof(map)); memset(match,0,sizeof(match)); int i; for (i=1;i<=n;i++) r[i].Get(); for (i=1;i<=n;i++) p[i].Get(); for (i=1;i<=n;i++) //建图 for (int j=1;j<=n;j++) { if (Judge(r[i],p[j])) map[j][i]=true; //有向边方向与match数组方向对应 } Deal (); } return 0; }
FOJ1202 信与信封问题
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <algorithm> using namespace std; const int N=105; bool map ; bool vis ; int match ; int n; bool Dfs (int u) { for (int v=1;v<=n;v++) if (vis[v] == false && map[u][v]) { vis[v]=true; if (match[v]==0 || Dfs(match[v])) { match[v]=u; return true; } } return false; } struct Point { int x,y; bool operator < (const Point& b) const { return x<b.x; } }data ; void Deal () { int i,sum=0,flag=0; for (i=1;i<=n;i++) { memset(vis,false,sizeof(vis)); if (Dfs(i)) sum++; } if (sum==n) { for (i=1;i<=n;i++) { int u=match[i]; if (u==0) continue; match[i]=0; map[u][i]=false; memset(vis,false,sizeof(vis)); if (Dfs(u)==false) { match[i]=u; data[flag].x=match[i]; data[flag++].y=i; } map[u][i]=true; } } if (flag==0) printf("none\n"); else { sort(data,data+flag); for (i=0;i<flag;i++) printf("%d %d\n",data[i].x,data[i].y); } printf("\n"); } int main () { #ifdef ONLINE_JUDGE #else freopen("read.txt","r",stdin); #endif while (~scanf("%d",&n)) { memset(map,true,sizeof(map)); memset(match,0,sizeof(match)); int a,b; while (scanf("%d%d",&a,&b),a||b) { map[a][b]=false; } Deal (); } return 0; }
二分图的必须边: 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");
|
|
解决这类题当然还有别的方法,但上述方法应该是一个不错的方法,在速度上POJ1486跑了0ms(这个题大家都0ms,看不出算法的优劣),FOJ1202我的代码只用0.01s就跑完了,暂列status里的第一,所以上述算法应该还行。
相关文章推荐
- POJ1486 Sorting Slides 二分图最大匹配 必要匹配
- POJ 1486 - Sorting Slides 二分匹配 必须边
- POJ-1486 Sorting Slides 二分图or贪心
- POJ1486_Sorting Slides_二分图匹配必须边
- 二分图必须边--poj1486
- POJ 1486 Sorting Slides【二分图匹配】
- POJ 1486 Sorting Slides 求二分图的必须边
- POJ 1486 Sorting Slides(二分图必须边)
- Poj 1486 Sorting Slides【二分匹配】
- POJ-1486-Sorting Slides
- poj 1486 Sorting Slides 二分匹配唯一性判定
- poj1486 Sorting Slides
- poj 1486 二分图最大匹配必须边
- poj 1486(求二分图形成匹配的必须边)
- poj 1486 二分图的必须边
- poj 1486(二分图必须边)
- POJ 1486 Sorting Slides 已翻译
- POJ 1486(二分图匹配)二分图的完全匹配的必须边
- poj1486 Sorting Slides 二分图匹配的必须边
- 信与信封问题(二分图完美匹配变式)