匈牙利算法

 

 

SAM I AM

 UVA - 11419 

二分图最小覆盖

二分图的最小顶点覆盖数等于最大匹配数。

且选择的顶点为: 

  从左边未被匹配的点开始扩展匈牙利树,标记树中的所有节点,取左边未被标记的和右边被标记的。

 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?'\n':' ');
84         for(int i=0;i<g.size();i++)
85             printf("r%d%c",g[i]+1,(i==g.size()-1?'\n':' '));
86         for(int i=0;i<b.size();i++)
87             printf("c%d%c",b[i]+1,(i==b.size()-1?'\n':' '));
88     }
89 
90 }
View Code

 

Guardian of Decency

 UVALive - 3415 

二分图最大独立集(顶点集)

最大独立集数=总点数-最小顶点覆盖数=总点数-最大匹配数

 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",n-ans);
76     }
77 
78 }
View Code

 

对比前两道题的建图,第一题因为行和列数值重复,所以一定不能加反向边,加了会认为是行到列的正向边

而第二题男女生编号不同所以可以加反向边

不过对于匈牙利算法,根本不需要加反向边,因为用不到


 

Taxi Cab Scheme

 UVALive - 3126

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",n-ans);
73     }
74 }
View Code

 

posted @ 2017-07-25 16:27  yijiull  阅读(256)  评论(0编辑  收藏  举报