http://acm.hdu.edu.cn/showproblem.php?pid=2853
题意:给一个n-m二分图,边权用一个n*m的矩阵表示,给出初始匹配,求二分图完美匹配相比初始匹配改变了几条边以及改变的数值
这类题的主要思想是增加原配边的权值,但又不影响最后结果。
步骤1:观察顶点数,每条边乘一个大于顶点数的数v
步骤2:对于原配边,每边加1(注意步骤2可以保证km()/v的结果与原结果相同)
步骤3:求完美匹配,答案为res,改变的边数=n-res%v(res%v表示完美匹配中有多少边属于原匹配),要求的完美匹配答案=res/v
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N=310; const int INF=0x3f3f3f3f; int nx,ny; int linker[N],lx[N],ly[N],slack[N]; int visx[N],visy[N],w[N][N]; int DFS(int x) { visx[x]=1; for(int y=1;y<=ny;y++){ if(visy[y]) continue; int tmp=lx[x]+ly[y]-w[x][y]; if(tmp==0){ visy[y]=1; if(linker[y]==-1 || DFS(linker[y])){ linker[y]=x; return 1; } }else if(slack[y]>tmp){ slack[y]=tmp; } } return 0; } int change ; int KM() { int i,j; memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for(i=1;i<=nx;i++) for(j=1,lx[i]=-INF;j<=ny;j++) if(w[i][j]>lx[i]) lx[i]=w[i][j]; for(int x=1;x<=nx;x++){ for(i=1;i<=ny;i++) slack[i]=INF; while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(DFS(x)) break; int d=INF; for(i=1;i<=ny;i++) if(!visy[i] && d>slack[i]) d=slack[i]; for(i=1;i<=nx;i++) if(visx[i]) lx[i]-=d; for(i=1;i<=ny;i++) if(visy[i]) ly[i]+=d; else slack[i]-=d; } } int res=0; for(i=1;i<=ny;i++) if(linker[i]!=-1) res+=w[linker[i]][i]; change=nx-res%200 ; return res/200; } int main() { while(~scanf("%d%d",&nx,&ny)) { for(int i=1;i<=nx;i++) for(int j=1;j<=ny;j++) { scanf("%d",&w[i][j]); w[i][j]*=200 ; } int res=0 ; for(int i=1 ;i<=nx ;i++) { int x ; scanf("%d",&x) ; res+=w[i][x] ; w[i][x]++ ; } int ans=KM(); printf("%d %d\n",change,ans-res/200); } return 0; }
http://acm.hdu.edu.cn/showproblem.php?pid=3315
与2853一样思路的题目,区别是这题图没有直接给,要先算一下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N=310; const int INF=0x3f3f3f3f; int n,nx,ny; int linker[N],lx[N],ly[N],slack[N]; int visx[N],visy[N],w[N][N]; int DFS(int x) { visx[x]=1; for(int y=1;y<=ny;y++){ if(visy[y]) continue; int tmp=lx[x]+ly[y]-w[x][y]; if(tmp==0){ visy[y]=1; if(linker[y]==-1 || DFS(linker[y])){ linker[y]=x; return 1; } }else if(slack[y]>tmp){ slack[y]=tmp; } } return 0; } int change ; int KM() { int i,j; memset(linker,-1,sizeof(linker)); memset(ly,0,sizeof(ly)); for(i=1;i<=nx;i++) for(j=1,lx[i]=-INF;j<=ny;j++) if(w[i][j]>lx[i]) lx[i]=w[i][j]; for(int x=1;x<=nx;x++){ for(i=1;i<=ny;i++) slack[i]=INF; while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(DFS(x)) break; int d=INF; for(i=1;i<=ny;i++) if(!visy[i] && d>slack[i]) d=slack[i]; for(i=1;i<=nx;i++) if(visx[i]) lx[i]-=d; for(i=1;i<=ny;i++) if(visy[i]) ly[i]+=d; else slack[i]-=d; } } int res=0; for(i=1;i<=ny;i++) if(linker[i]!=-1) res+=w[linker[i]][i]; if(res<=0)return -1 ; change=nx-res%200 ; return res/200; } int V[N],H1[N],A1[N],H2[N],A2[N] ; int main() { while(~scanf("%d",&n),n) { nx=ny=n ; for(int i=1 ;i<=n ;i++) scanf("%d",&V[i]) ; for(int i=1 ;i<=n ;i++) scanf("%d",&H1[i]) ; for(int i=1 ;i<=n ;i++) scanf("%d",&H2[i]) ; for(int i=1 ;i<=n ;i++) scanf("%d",&A1[i]) ; for(int i=1 ;i<=n ;i++) scanf("%d",&A2[i]) ; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int x ; x=H1[i]/A2[j] ; if(H1[i]%A2[j])x++ ; if(x*A1[i]>=H2[j])w[i][j]=V[i]*200 ; else w[i][j]=(-V[i]*200) ; } for(int i=1 ;i<=n ;i++) w[i][i]++ ; int ans=KM(); if(ans==-1)puts("Oh, I lose my dear seaco!") ; else printf("%d %.3lf%%\n",ans,(nx-change)*100.0/n); } return 0; }