题意:找出幻灯片与编号唯一对应的情况
思路: 1:求最大匹配,若小于n,则答案为none,否则转2
(不过我代码没有事先判断一开始的最大匹配数是否<n,但这样也过了,估计给的数据最大匹配数一定为n吧)
2:删除一条边e,以e的一个端点找增广路,若不能找到增广路则e是必须边
也就是重新计算匹配数,如果匹配数减少说明此边是必须也是唯一的. 如果一样说明这边存不存在都行.转3
3:恢复原图,继续步骤2,直到每条边都被删除过
刚开始看网上别人的代码,有一点看不懂,那就是为什么只要找到唯一对应的就输出。
而不是最后当确定所有的幻灯片都唯一确定后再一起输出,否则只要有一个不唯一确定就输出"none" 。
后来网上查了查,发现:只要能推出多少唯一对应的,就唯一显示多少,只有全部不能推出来才显示“none”!!!!!!!!!! 坑死我了啊!
举个例子:
5
10 40 40 70
20 50 30 60
30 60 20 50
45 70 10 40
45 70 10 40
25 55
35 55
35 45
55 25
65 25 答案: Heap 1 (C,3)
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <queue> using namespace std; int n,cnt; bool flag; int edge[50][50]; //edge[i][j]表示j点在第i张幻灯片里 int used[50]; int matchx[50]; struct Slide{ int xmin,xmax,ymin,ymax; }slide[50]; struct Num{ int x,y; }num[50] ; void deal(){ for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if((slide[i].xmin<=num[j].x)&&(num[j].x<=slide[i].xmax)&&(slide[i].ymin<=num[j].y)&&(num[j].y<=slide[i].ymax)) edge[i][j]=1; } } } bool dfs(int k){ for(int i=0;i<n;i++){ if(edge[k][i]&&!used[i]){ used[i]=1; if(matchx[i]==-1 || dfs(matchx[i])){ matchx[i]=k; return true; } } } return false; } int hungry(){ cnt=0; memset(matchx,-1,sizeof(matchx)); for(int i=0;i<n;i++){ memset(used,0,sizeof(used)); if(dfs(i)){ cnt++; } } return cnt; } int main() { int cases=0; while(scanf("%d",&n)!=EOF){ if(n==0) break; memset(edge,0,sizeof(edge)); flag=false; cases++; for(int i=0;i<n;i++){ scanf("%d%d%d%d",&slide[i].xmin,&slide[i].xmax,&slide[i].ymin,&slide[i].ymax); } for(int i=0;i<n;i++){ scanf("%d%d",&num[i].x,&num[i].y); } deal(); printf("Heap %d ",cases); for(int i=0;i<n;i++){ for(int j=0;j<n;j++){ if(edge[i][j]==0) continue; edge[i][j]=0; //如果删去边(i,j),匹配数减少,说明是必须边。 if(hungry()<n){ flag=true; char ch='A'+i; printf("(%c,%d) ",ch,j+1); } edge[i][j]=1; } } if(!flag){ printf("none "); } else{ printf(" "); } } return 0; }