Swap HDU 2819
此题主要让我们发现匈牙利算法中记录匹配点编号数组的应用:
此数组记录的是左边的第几个与右边的第几个匹配!
因为要求对角线匹配,那么进行两两移位就行了。。。
注意的是:你把横坐标的数放在左边,竖坐标的数放在右边的话,是移动C。
反过来就是移动R。
具体看代码:(注意红色字体部分)
1 #include<iostream> 2 #include<algorithm> 3 #include<stdio.h> 4 #include<string.h> 5 using namespace std; 6 int a[105][105],b[105],vis[105],a1[105],b1[105],n; 7 int dfs(int x) 8 { 9 for(int i=1;i<=n;i++) 10 if(a[i][x]&&!vis[i]) 11 { 12 vis[i]=1; 13 if(b[i]==-1||dfs(b[i])) 14 { 15 b[i]=x; 16 return 1; 17 } 18 } 19 return 0; 20 } 21 int main() 22 { 23 int i,j,ans,sum; 24 while(scanf("%d",&n)!=EOF) 25 { 26 for(i=1;i<=n;i++) 27 for(j=1;j<=n;j++) 28 scanf("%d",&a[i][j]);//这里说明横坐标在左边(i),竖坐标在右边(j) 29 ans=0; 30 memset(b,-1,sizeof(b)); 31 for(i=1;i<=n;i++) 32 { 33 memset(vis,0,sizeof(vis)); 34 if(dfs(i)) 35 ans++; 36 } 37 if(ans<n) 38 { 39 printf("-1 "); 40 continue; 41 } 42 sum=0; 43 for(i=1;i<=n;i++) 44 { 45 for(j=i;j<=n;j++) 46 if(b[j]==i) 47 break; 48 if(i!=j) 49 { 50 sum++; 51 a1[sum]=i; 52 b1[sum]=j; 53 swap(b[i],b[j]); 54 } 55 }//移位的话,是一左边为基点,一个一个把左边的移好位 56 printf("%d ",sum); 57 for(i=1;i<=sum;i++) 58 printf("R %d %d ",a1[i],b1[i]); 59 } 60 return 0; 61 }
但是只要改一点点就行了!!!
1 #include<iostream> 2 #include<algorithm> 3 #include<stdio.h> 4 #include<string.h> 5 using namespace std; 6 int a[105][105],b[105],vis[105],a1[105],b1[105],n; 7 int dfs(int x) 8 { 9 for(int i=1;i<=n;i++) 10 if(a[x][i]&&!vis[i]) 11 { 12 vis[i]=1; 13 if(b[i]==-1||dfs(b[i])) 14 { 15 b[i]=x; 16 return 1; 17 } 18 } 19 return 0; 20 } 21 int main() 22 { 23 int i,j,ans,sum; 24 while(scanf("%d",&n)!=EOF) 25 { 26 for(i=1;i<=n;i++) 27 for(j=1;j<=n;j++) 28 scanf("%d",&a[i][j]); 29 ans=0; 30 memset(b,-1,sizeof(b)); 31 for(i=1;i<=n;i++) 32 { 33 memset(vis,0,sizeof(vis)); 34 if(dfs(i)) 35 ans++; 36 } 37 if(ans<n) 38 { 39 printf("-1 "); 40 continue; 41 } 42 sum=0; 43 for(i=1;i<=n;i++) 44 { 45 for(j=i;j<=n;j++) 46 if(b[j]==i) 47 break; 48 if(i!=j) 49 { 50 sum++; 51 a1[sum]=i; 52 b1[sum]=j; 53 swap(b[i],b[j]); 54 } 55 } 56 printf("%d ",sum); 57 for(i=1;i<=sum;i++) 58 printf("C %d %d ",a1[i],b1[i]); 59 } 60 return 0; 61 }
但是我发现一个致命错误!!
上面的第一个代码:
没有进入dfs()的是横坐标,但是dfs()里面求的是以右括号的为定值,把左括号进行循环找出这个b[i]=x;
可以发现b[i]表示横坐标,那么下面移位的是b[i],则就是‘R’!!
Sorting Slides POJ 1486
这题主要考如何判断这个匹配是唯一的?(进行删边处理)
步骤:
1:求最大匹配,匹配边集合E
2:删除E中的一条边e,以e的一个端点找增广路,若不能找到增广路则e是必须边
3:恢复原图以及E,继续步骤2,直到E中的每条边都被删除过
分析:因为每个顶点只出现一次,那么每个顶点只关联两个顶点入度顶点和出度顶点,所以构造二分图,将一个点u拆成u,u'。那么对于这个二分图如果存在着完美匹配的话,那么原图中一定存在若干个环,环中包含每个顶点,对于权值之和最小,只需求最小权匹配即可。
这个题目不用求出匹配数是多少。。。
直接进行删边,有唯一的就输出。。。如果一个都没有就输出“none”。
1 #include<iostream> 2 #include<algorithm> 3 #include<stdio.h> 4 #include<string.h> 5 using namespace std; 6 int a1[105][105],vis[105],b[105],n; 7 struct line 8 { 9 int x1; 10 int x2; 11 int y1; 12 int y2; 13 }a[105]; 14 int dfs(int x) 15 { 16 for(int i=1;i<=n;i++) 17 if(a1[x][i]&&!vis[i]) 18 { 19 vis[i]=1; 20 if(b[i]==-1||dfs(b[i])) 21 { 22 b[i]=x; 23 return 1; 24 } 25 } 26 return 0; 27 } 28 int main() 29 { 30 int d=0,i,j,x1,y1; 31 while(scanf("%d",&n)!=EOF) 32 { 33 if(n==0) 34 break; 35 if(d) 36 printf(" "); 37 for(i=1;i<=n;i++) 38 scanf("%d%d%d%d",&a[i].x1,&a[i].x2,&a[i].y1,&a[i].y2); 39 memset(a1,0,sizeof(a1)); 40 for(i=1;i<=n;i++) 41 { 42 scanf("%d%d",&x1,&y1); 43 for(j=1;j<=n;j++) 44 if(a[j].x1<x1&&a[j].x2>x1&&a[j].y1<y1&&a[j].y2>y1) 45 a1[i][j]=1; 46 } 47 memset(b,-1,sizeof(b)); 48 for(i=1;i<=n;i++) 49 { 50 memset(vis,0,sizeof(vis)); 51 dfs(i); 52 } 53 printf("Heap %d ",++d); 54 int flag=0; 55 for(i=1;i<=n;i++)//****************** 56 { 57 int tmp=b[i]; 58 b[i]=-1; 59 a1[tmp][i]=0; 60 memset(vis,0,sizeof(vis));//注意初始为零 61 if(!dfs(tmp)) 62 { 63 if(flag) 64 printf(" "); 65 printf("(%c,%d)",'A'+i-1,tmp);//注意的是把代表字母放到右边,那么判断直接输出就行了 66 b[i]=tmp; 67 flag=1; 68 } 69 a1[tmp][i]=1; 70 }//*********************删边处理 71 if(flag==0) 72 printf("none "); 73 else 74 printf(" "); 75 76 } 77 return 0; 78 }
之后来个最小权匹配的例子:
Tour HDU 3488
这里注意判断时,和输出时:(红色字体部分)
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 int inf=100000005; 7 int lx[205],ly[205],a[205][205],vix[205],viy[205],slack[205],link[205],n; 8 int dfs(int x) 9 { 10 vix[x]=1; 11 for(int i=1;i<=n;i++) 12 { 13 if(viy[i]) 14 continue; 15 if(a[x][i]!=-inf&&lx[x]+ly[i]==a[x][i]) 16 { 17 viy[i]=1; 18 if(link[i]==-1||dfs(link[i])) 19 { 20 link[i]=x; 21 return 1; 22 } 23 } 24 else if(a[x][i]!=-inf)//这里知道一定有完美匹配了!如果没有就是个死循环 25 { 26 if(lx[x]+ly[i]-a[x][i]<slack[i]) 27 slack[i]=lx[x]+ly[i]-a[x][i]; 28 } 29 } 30 return 0; 31 } 32 int main() 33 { 34 int t,m,a1,b1,c1,s,i,j; 35 scanf("%d",&t); 36 while(t--) 37 { 38 scanf("%d%d",&n,&m); 39 for(i=1;i<=n;i++) 40 for(j=1;j<=n;j++) 41 a[i][j]=-inf; 42 while(m--) 43 { 44 scanf("%d%d%d",&a1,&b1,&c1); 45 if(a[a1][b1]<-c1) 46 a[a1][b1]=-c1; 47 } 48 memset(link,-1,sizeof(link)); 49 memset(lx,-inf,sizeof(lx)); 50 memset(ly,0,sizeof(ly)); 51 for(i=1;i<=n;i++) 52 for(j=1;j<=n;j++) 53 if(a[i][j]>lx[i]) 54 lx[i]=a[i][j]; 55 for(i=1;i<=n;i++) 56 { 57 for(j=1;j<=n;j++) 58 slack[j]=inf; 59 while(1) 60 { 61 memset(vix,0,sizeof(vix)); 62 memset(viy,0,sizeof(viy)); 63 if(dfs(i)) 64 break; 65 int d=inf; 66 for(j=1;j<=n;j++) 67 if(!viy[j]&&d>slack[j]) 68 d=slack[j]; 69 for(j=1;j<=n;j++) 70 { 71 if(vix[j]) 72 lx[j]-=d; 73 if(viy[j]) 74 ly[j]+=d; 75 else 76 slack[j]-=d; 77 } 78 } 79 } 80 s=0; 81 for(i=1;i<=n;i++) 82 if(link[i]!=-1) 83 s+=a[link[i]][i]; 84 printf("%d ",-s); 85 } 86 return 0; 87 }
Cyclic Tour HDU1853
这个题目和上面的差不多,但是他不一定有完美匹配!!!
所以用上面的方法做不出来!!!
所以就要套用模板什么都不用改!在最后进行判断就行了!
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<string.h> 5 using namespace std; 6 int inf=100000005; 7 int lx[205],ly[205],a[205][205],vix[205],viy[205],slack[205],link[205],n; 8 int dfs(int x) 9 { 10 vix[x]=1; 11 for(int i=1;i<=n;i++) 12 { 13 if(viy[i]) 14 continue; 15 if(lx[x]+ly[i]==a[x][i]) 16 { 17 viy[i]=1; 18 if(link[i]==-1||dfs(link[i])) 19 { 20 link[i]=x; 21 return 1; 22 } 23 } 24 else 25 { 26 if(lx[x]+ly[i]-a[x][i]<slack[i]) 27 slack[i]=lx[x]+ly[i]-a[x][i]; 28 } 29 } 30 return 0; 31 } 32 int main() 33 { 34 int m,a1,b1,c1,s,i,j; 35 while(scanf("%d%d",&n,&m)!=EOF) 36 { 37 for(i=1;i<=n;i++) 38 for(j=1;j<=n;j++) 39 a[i][j]=-inf; 40 while(m--) 41 { 42 scanf("%d%d%d",&a1,&b1,&c1); 43 if(a[a1][b1]<-c1) 44 a[a1][b1]=-c1; 45 } 46 memset(link,-1,sizeof(link)); 47 memset(lx,-inf,sizeof(lx)); 48 memset(ly,0,sizeof(ly)); 49 for(i=1;i<=n;i++) 50 for(j=1;j<=n;j++) 51 if(a[i][j]>lx[i]) 52 lx[i]=a[i][j]; 53 for(i=1;i<=n;i++) 54 { 55 for(j=1;j<=n;j++) 56 slack[j]=inf; 57 while(1) 58 { 59 memset(vix,0,sizeof(vix)); 60 memset(viy,0,sizeof(viy)); 61 if(dfs(i)) 62 break; 63 int d=inf; 64 for(j=1;j<=n;j++) 65 if(!viy[j]&&d>slack[j]) 66 d=slack[j]; 67 for(j=1;j<=n;j++) 68 { 69 if(vix[j]) 70 lx[j]-=d; 71 if(viy[j]) 72 ly[j]+=d; 73 else 74 slack[j]-=d; 75 } 76 } 77 } 78 s=0; 79 int s1=0; 80 for(i=1;i<=n;i++)//*********** 81 { 82 if(link[i]==-1||a[link[i]][i]==-inf) 83 { 84 s1=1; 85 break; 86 } 87 s+=a[link[i]][i]; 88 }//**************** 89 if(s1==1) 90 printf("-1 "); 91 else 92 printf("%d ",-s); 93 } 94 return 0; 95 }