• 匈牙利算法


    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?'
    ':' ');
    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 }
    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-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-ans);
    73     }
    74 }
    View Code
  • 相关阅读:
    2013年2月最后一周
    linux虚拟机与winodows共享文件夹linux安装VMware tools
    汇编语言 手记8
    汇编语言 手记9
    虚拟机vmware与本地磁盘共享方法
    生活里多少会有些迷茫
    《恋爱厚黑学》杨冰阳
    2012年读书目录
    2013年2月第2个周末
    JBOSSJNDI日常
  • 原文地址:https://www.cnblogs.com/yijiull/p/7234869.html
Copyright © 2020-2023  润新知