题意:给出一个矩阵和一些矩阵上的点,选择最少的行或列把给出的点覆盖。
思路:把行看成一个点集,列看成另一个点集,每个给出点构造一条这两个点集中的一条边。我们的问题就变成了选择最少的点把所有的边覆盖。很显然这就是一个最大独立点集问题,可用最大匹配求解。
匈牙利匹配算法:
View Code
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 #define N 10010 6 #define M 20020 7 struct edge{ 8 int to,next; 9 }e[M]; 10 int pre[N],visit[N],p[N]; 11 int cnt; 12 void add(int a,int b) 13 { 14 e[cnt].next=pre[a]; 15 e[cnt].to=b; 16 pre[a]=cnt++; 17 } 18 bool dfs(int u) 19 { 20 for(int edg=pre[u];edg!=0;edg=e[edg].next) 21 { 22 int v=e[edg].to; 23 if(visit[v])continue; 24 visit[v]=1; 25 if(!p[v]||dfs(p[v])) 26 { 27 p[v]=u; 28 return true; 29 } 30 } 31 return false; 32 } 33 int main() 34 { 35 int n,m; 36 while(scanf("%d%d",&n,&m)!=EOF) 37 { 38 cnt=1; 39 int c=0; 40 memset(p,0,sizeof(p)); 41 memset(pre,0,sizeof(pre)); 42 for(int i=1;i<=m;i++){ 43 int a,b; 44 scanf("%d%d",&a,&b); 45 add(a,b+n); 46 add(b+n,a); 47 } 48 49 for(int i=1;i<=n;i++) 50 { 51 memset(visit,0,sizeof(visit)); 52 if(dfs(i))c++; 53 } 54 printf("%d\n",c); 55 } 56 return 0; 57 }
最大流dinic算法(邻接矩阵实现):
View Code
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 #define inf 0x3f3f3f3f 6 #define N 1010 7 int S,T,L,R; 8 int flow[N][N],cap[N][N],level[N],q[N]; 9 bool dinic_bfs() 10 { 11 int rear=0,tail=1; 12 q[0]=S; 13 memset(level,0,sizeof(level)); 14 level[S]=1; 15 while(rear<tail) 16 { 17 int u=q[rear++]; 18 for(int i=L;i<=R;i++) 19 { 20 if(!level[i]&&cap[u][i]-flow[u][i]>0) 21 { 22 level[i]=level[u]+1; 23 q[tail++]=i; 24 } 25 } 26 } 27 return level[T]!=0; 28 } 29 int dinic_dfs(int u,int cp) 30 { 31 int tmp=cp; 32 if(u==T)return cp; 33 for(int i=L;i<=R&&tmp;i++) 34 { 35 if(level[i]==level[u]+1&&cap[u][i]-flow[u][i]>0) 36 { 37 int t=dinic_dfs(i,min(tmp,cap[u][i]-flow[u][i])); 38 flow[u][i]+=t; 39 flow[i][u]-=t; 40 tmp-=t; 41 } 42 } 43 return cp-tmp; 44 } 45 int dinic() 46 { 47 int tf=0,f; 48 while(dinic_bfs()) 49 { 50 while(f=dinic_dfs(S,inf)) 51 { 52 tf+=f; 53 } 54 } 55 return tf; 56 } 57 int main() 58 { 59 int n,m; 60 while(scanf("%d%d",&n,&m)!=EOF) 61 { 62 memset(flow,0,sizeof(flow)); 63 memset(cap,0,sizeof(cap)); 64 S=L=0; 65 T=R=2*n+1; 66 for(int i=1;i<=m;i++) 67 { 68 int a,b; 69 scanf("%d%d",&a,&b); 70 cap[a][b+n]=1; 71 } 72 for(int i=1;i<=n;i++) 73 { 74 cap[S][i]=1; 75 cap[i+n][T]=1; 76 } 77 printf("%d\n",dinic()); 78 } 79 return 0; 80 }
最大流dinic算法(邻接表实现):
View Code
1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 using namespace std; 5 #define N 1010 6 #define M 20020 7 #define inf 0x3f3f3f3f 8 struct edge{ 9 int to,next,cap,flow; 10 }e[M]; 11 int pre[N],level[N],q[N]; 12 int cnt,S,T; 13 void add(int a,int b,int c) 14 { 15 e[cnt].to=b; 16 e[cnt].next=pre[a]; 17 e[cnt].cap=c; 18 e[cnt].flow=0; 19 pre[a]=cnt++; 20 } 21 bool dinic_bfs() 22 { 23 int rear=0,tail=1; 24 q[0]=S; 25 memset(level,0,sizeof(level)); 26 level[S]=1; 27 while(rear<tail) 28 { 29 int u=q[rear++]; 30 for(int edg=pre[u];edg!=0;edg=e[edg].next) 31 { 32 int v=e[edg].to; 33 if(!level[v]&&e[edg].cap>e[edg].flow) 34 { 35 level[v]=level[u]+1; 36 q[tail++]=v; 37 } 38 } 39 } 40 return level[T]!=0; 41 } 42 int dinic_dfs(int u,int cp) 43 { 44 int tmp=cp; 45 if(u==T)return cp; 46 for(int edg=pre[u];tmp&&edg!=0;edg=e[edg].next) 47 { 48 int v=e[edg].to; 49 if(level[v]==level[u]+1&&e[edg].cap>e[edg].flow) 50 { 51 int t=dinic_dfs(v,min(tmp,e[edg].cap-e[edg].flow)); 52 e[edg].flow+=t; 53 e[edg^1].flow-=t; 54 tmp-=t; 55 } 56 } 57 return cp-tmp; 58 } 59 int dinic() 60 { 61 int tf=0,f; 62 while(dinic_bfs()) 63 { 64 //cout<<1<<endl; 65 while(f=dinic_dfs(S,inf)) 66 { 67 //cout<<f<<endl; 68 tf+=f; 69 } 70 } 71 return tf; 72 } 73 int main() 74 { 75 int n,m; 76 while(scanf("%d%d",&n,&m)!=EOF) 77 { 78 memset(pre,0,sizeof(pre)); 79 int cnt=2; 80 S=0;T=2*n+1; 81 for(int i=1;i<=m;i++) 82 { 83 int a,b; 84 scanf("%d%d",&a,&b); 85 add(a,b+n,1); 86 add(b+n,a,0); 87 } 88 for(int i=1;i<=n;i++) 89 { 90 add(S,i,1); 91 add(i,S,0); 92 add(i+n,T,1); 93 add(T,i+n,0); 94 } 95 printf("%d\n",dinic()); 96 } 97 return 0; 98 }