SAM I AM
二分图最小覆盖
二分图的最小顶点覆盖数等于最大匹配数。
且选择的顶点为:
从左边未被匹配的点开始扩展匈牙利树,标记树中的所有节点,取左边未被标记的和右边被标记的。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define CLR(m,a) memset(m,a,sizeof(m)) 4 const int maxv=1010; 5 int r,c,n; 6 struct Edge 7 { 8 int v,nex; 9 }e[maxv*maxv<<1]; 10 int head[maxv]; 11 int cnt=0; 12 void init() 13 { 14 CLR(head,-1); 15 cnt=0; 16 } 17 void add(int u,int v) 18 { 19 e[cnt].v=v; 20 e[cnt].nex=head[u]; 21 head[u]=cnt++; 22 } 23 24 int vb[maxv],vg[maxv],mcb[maxv],mcg[maxv]; 25 vector<int> b,g; 26 int Hungary(int u) 27 { 28 vg[u]=1; 29 for(int i=head[u];~i;i=e[i].nex) 30 { 31 int v=e[i].v; 32 if(!vb[v]) 33 { 34 vb[v]=1; 35 if(mcb[v]==-1||Hungary(mcb[v])) 36 { 37 mcb[v]=u; 38 mcg[u]=v; 39 return 1; 40 } 41 42 } 43 } 44 return 0; 45 } 46 void Mincover() 47 { 48 CLR(vb,0); 49 CLR(vg,0); 50 for(int i=0;i<r;i++) 51 if(mcg[i]==-1) Hungary(i); 52 for(int i=0;i<r;i++) 53 if(!vg[i]) g.push_back(i); 54 for(int i=0;i<c;i++) 55 if(vb[i]) b.push_back(i); 56 57 return ; 58 } 59 int main() 60 { 61 while(scanf("%d%d%d",&r,&c,&n)&&(r+c+n)) 62 { 63 init(); 64 b.clear(); 65 g.clear(); 66 int u,v; 67 for(int i=0;i<n;i++) 68 { 69 scanf("%d%d",&u,&v); 70 u--;v--; 71 add(u,v); 72 } 73 int ans=0; 74 CLR(mcb,-1); 75 CLR(mcg,-1); 76 for(int i=0;i<r;i++) 77 { 78 CLR(vb,0); 79 CLR(vg,0); 80 if(Hungary(i)) ans++; 81 } 82 Mincover(); 83 printf("%d%c",ans,ans==0?' ':' '); 84 for(int i=0;i<g.size();i++) 85 printf("r%d%c",g[i]+1,(i==g.size()-1?' ':' ')); 86 for(int i=0;i<b.size();i++) 87 printf("c%d%c",b[i]+1,(i==b.size()-1?' ':' ')); 88 } 89 90 }
Guardian of Decency
二分图最大独立集(顶点集)
最大独立集数=总点数-最小顶点覆盖数=总点数-最大匹配数
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define CLR(m,a) memset(m,a,sizeof(m)) 4 const int maxv=510; 5 6 struct node 7 { 8 int age; 9 char c; 10 char music[120]; 11 char sport[120]; 12 }p[maxv]; 13 struct Edge 14 { 15 int v,nex; 16 }e[maxv*maxv<<1]; 17 int head[maxv]; 18 int cnt=0; 19 void init() 20 { 21 CLR(head,-1); 22 cnt=0; 23 } 24 void add(int u,int v) 25 { 26 e[cnt].v=v; 27 e[cnt].nex=head[u]; 28 head[u]=cnt++; 29 } 30 31 int mcb[maxv],mcg[maxv],vb[maxv],vg[maxv]; 32 int n; 33 int Hungry(int u) 34 { 35 vg[u]=1; 36 for(int i=head[u];~i;i=e[i].nex) 37 { 38 int v=e[i].v; 39 if(vb[v]) continue; 40 vb[v]=1; 41 if(mcb[v]==-1||Hungry(mcb[v])) 42 { 43 mcb[v]=u; 44 return 1; 45 } 46 } 47 return 0; 48 } 49 int main() 50 { 51 int t; 52 scanf("%d",&t); 53 while(t--) 54 { 55 init(); 56 scanf("%d",&n); 57 for(int i=0;i<n;i++) 58 scanf("%d %c%s%s",&p[i].age,&p[i].c,p[i].music,p[i].sport); 59 for(int i=0;i<n;i++) 60 for(int j=0;j<n;j++) if(p[i].c=='M'&&p[j].c!='M') 61 if(abs(p[i].age-p[j].age)<=40&&strcmp(p[i].music,p[j].music)==0&&strcmp(p[i].sport,p[j].sport)!=0) 62 { 63 add(i,j); 64 // add(j,i); //用不到反向边 65 } 66 int ans=0; 67 CLR(mcb,-1); 68 CLR(mcg,-1); 69 for(int i=0;i<n;i++) if(p[i].c=='M') 70 { 71 CLR(vb,0); 72 CLR(vg,0); 73 if(Hungry(i)) ans++; 74 } 75 printf("%d ",n-ans); 76 } 77 78 }
对比前两道题的建图,第一题因为行和列数值重复,所以一定不能加反向边,加了会认为是行到列的正向边
而第二题男女生编号不同所以可以加反向边
不过对于匈牙利算法,根本不需要加反向边,因为用不到
Taxi Cab Scheme
DAG最小路径覆盖
首先要明白什么是最小路径覆盖
就是在图中找尽量少的路径,使得每个节点恰好在一条路径上
换句话说,不同的路径不能有公共点
单独的点也可以作为一条路径
解法:把每个点都拆成两个点i和i'
如果点i可以到点j,那么连一条边从i到j'
求得该图的最大匹配m,则最小路径覆盖就是n-m
证明见大白书p357
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define CLR(m,a) memset(m,a,sizeof(m)) 4 const int maxv=510; 5 int n; 6 struct node 7 { 8 int h,m,x1,x2,y1,y2; 9 }p[maxv]; 10 struct Edge 11 { 12 int v,nex; 13 }e[maxv*maxv]; 14 int head[maxv]; 15 int cnt=0; 16 void init() 17 { 18 CLR(head,-1); 19 cnt=0; 20 } 21 void add(int u,int v) 22 { 23 e[cnt].v=v; 24 e[cnt].nex=head[u]; 25 head[u]=cnt++; 26 } 27 int vb[maxv],mc[maxv]; 28 int Hungry(int u) 29 { 30 for(int i=head[u];~i;i=e[i].nex) 31 { 32 int v=e[i].v; 33 if(vb[v]) continue; 34 vb[v]=1; 35 if(mc[v]==-1||Hungry(mc[v])) 36 { 37 mc[v]=u; 38 return 1; 39 } 40 } 41 return 0; 42 } 43 int main() 44 { 45 int t; 46 scanf("%d",&t); 47 while(t--) 48 { 49 init(); 50 scanf("%d",&n); 51 for(int i=0;i<n;i++) 52 scanf("%d:%d%d%d%d%d",&p[i].h,&p[i].m,&p[i].x1,&p[i].y1,&p[i].x2,&p[i].y2); 53 54 for(int i=0;i<n;i++) 55 { 56 node tp=p[i]; 57 int st=tp.h*60+tp.m+abs(tp.x1-tp.x2)+abs(tp.y1-tp.y2); 58 for(int j=0;j<n;j++) if(i!=j) 59 { 60 int ed=st+abs(tp.x2-p[j].x1)+abs(tp.y2-p[j].y1); 61 if(ed<p[j].h*60+p[j].m) add(i,j); 62 } 63 } 64 65 CLR(mc,-1); 66 int ans=0; 67 for(int i=0;i<n;i++) 68 { 69 CLR(vb,0); 70 if(Hungry(i)) ans++; 71 } 72 printf("%d ",n-ans); 73 } 74 }