有向环覆盖问题

转载自这里

 

  给你一个N个顶点M条边的带权有向图,要你把该图分成一个或多个不相交的有向环。且所有定点都被有向环覆盖。问你该有向环所有权值的总和最小是多少?

  答案就是:有向环最大权值覆盖=最优匹配。

   如果,改为无向图,问你无向环最大权值覆盖?答案也是一样的。只是在建图的时候把有向改为无向即可。

 

分析:

   我们把任意一个顶点i都分成两个,即i和i’. 如果原图存在i->j的边,那么二分图有i->j’的边.

       下面我们要引出几条结论:

        ① 如果原图能由多个不相交的有向环覆盖,那么二分图必然存在完备匹配。他们互为充要条件,也就是说如果二分图存在完备匹配,那么原图必定能由几个不想交的有向环覆盖. 

        ② 如果原图存在权值最大的有向环覆盖,那么二分图的最优匹配一定就是这个值。即权值最大的有向环覆盖在数值上等于改图的最优匹配值。

      因为该有向环覆盖对应了一个二分图的完备匹配,而该完备匹配的权值就等于该有向环覆盖的权值,所以最优匹配不可能丢失该最大权值的匹配。

 

  (假设原图的有向环为(1->2->3->1) and(6->5->4->6),那么二分图的完备匹配就是1->2’ 2->3’ 3->1’ 6->5’ 5->4’ 4->6’)

   (假设二分图的完备匹配是1->2’ 2->3’ 3->1’ 6->5’ 5->4’ 4->6’那么原图的有向环为(1->2->3->1) and (6->5->4->6))

 

 

例如HDU1853:

       现在原题要求的是最小权匹配,我们把所有已知边的权值都取负数,且那些不存在的边我们取-INF(负无穷). 如果完备匹配存在,那么我们求出的最优匹配权值的绝对值 肯定<INF. 且该绝对值就是最小权值匹配.

       如果完备匹配不存在,那么最优匹配权值的绝对值肯定>INF.(想想是不是) 或者这么说,如果最终求得的匹配中,有任何一个匹配边用了权值为负无穷的边,那么最优匹配不存在(即完备匹配不存在)

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<queue>
 4 #define _Clr(x, y) memset(x, y, sizeof(x))
 5 #define INF 0x3f3f3f3f
 6 #define N 1005
 7 using namespace std;
 8 
 9 int mat[N][N], match[N];
10 int lx[N], ly[N];
11 int slack[N];
12 bool used_x[N], used_y[N];
13 int n, m;
14 
15 bool dfs(int x)
16 {
17     used_x[x] = true;
18     for(int i=1; i<=n; i++)
19     {
20         if(used_y[i]) continue;
21         int t = lx[x] + ly[i] - mat[x][i];
22         if(t==0)
23         {
24             used_y[i] = true;
25             if(match[i]==-1 || dfs(match[i]))
26             {
27                 match[i] = x;
28                 return true;
29             }
30         }
31         else slack[i] = min(slack[i], t);
32     }
33     return false;
34 }
35 
36 int KM()
37 {
38     _Clr(match, -1);
39     _Clr(ly, 0);
40     for(int i=1, j; i<=n; i++)
41         for(j=1, lx[i]=-INF; j<=n; j++)
42             lx[i] = max(lx[i], mat[i][j]);
43     for(int x=1; x<=n; x++)
44     {
45         _Clr(slack, INF);
46         while(1)
47         {
48             _Clr(used_x, 0);
49             _Clr(used_y, 0);
50             if(dfs(x)) break;
51             int d=INF;
52             for(int i=1; i<=n; i++)
53                 if(!used_y[i] && d>slack[i])
54                     d = slack[i];
55             for(int i=1; i<=n; i++)
56                 if(used_x[i])
57                     lx[i] -= d;
58             for(int i=1; i<=n; i++)
59                 if(used_y[i])
60                     ly[i] += d;
61                 else slack[i] -= d;
62         }
63     }
64     int ans=0;
65     for(int i=1; i<=n; i++)
66     {
67         if(match[i]==-1 || mat[match[i]][i]==-INF) return -1;
68         ans += mat[match[i]][i];
69     }
70     return -ans;
71 }
72 int main()
73 {
74     int m, a, b, c;
75     while(~scanf("%d%d", &n, &m))
76     {
77         for(int i=1; i<=n; i++)
78         for(int j=1; j<=n; j++)
79             mat[i][j]=-INF;
80         while(m--)
81         {
82             scanf("%d%d%d", &a, &b, &c);
83             mat[a][b] = max(mat[a][b], -c);
84         }
85         printf("%d\n", KM());
86     }
87     return 0;
88 }

 

例如:HDU 3435

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define _Clr(x, y) memset(x, y, sizeof(x))
 5 #define INF 0x3f3f3f3f
 6 #define N 1010
 7 using namespace std;
 8 
 9 int mat[N][N], match[N];
10 int lx[N], ly[N];
11 int slack[N], n;
12 bool used_x[N], used_y[N];
13 
14 bool dfs(int x)
15 {
16     used_x[x] = true;
17     for(int i=1; i<=n; i++)
18     {
19         if(used_y[i]) continue;
20         int t=lx[x]+ly[i]-mat[x][i];
21         if(t==0)
22         {
23             used_y[i] = true;
24             if(match[i]==-1 || dfs(match[i]))
25             {
26                 match[i] = x;
27                 return true;
28             }
29         }
30         else slack[i] = min(slack[i], t);
31     }
32     return false;
33 }
34 
35 int KM()
36 {
37     _Clr(match, -1);
38     _Clr(ly, 0);
39     for(int i=1, j=1; i<=n; i++)
40     for(j=1, lx[i]=-INF; j<=n; j++)
41         lx[i] = max(lx[i], mat[i][j]);
42     for(int x=1; x<=n; x++)
43     {
44         _Clr(slack, INF);
45         while(1)
46         {
47             _Clr(used_x, 0);
48             _Clr(used_y, 0);
49             if(dfs(x)) break;
50             int d=INF;
51             for(int i=1; i<=n; i++)
52                 if(!used_y[i] && slack[i]<d)
53                     d = slack[i];
54             for(int i=1; i<=n; i++)
55                 if(used_x[i]) lx[i] -= d;
56             for(int i=1; i<=n; i++)
57                 if(used_y[i]) ly[i] += d;
58                 else slack[i] -= d;
59         }
60     }
61     int ans=0;
62     for(int i=1; i<=n; i++)
63     {
64         if(match[i]==-1 || mat[match[i]][i]==-INF) return 0;
65         ans += mat[match[i]][i];
66     }
67     return ans;
68 }
69 
70 int main()
71 {
72     int m, T, a, b, c;
73     int lop=1;
74     scanf("%d", &T);
75     while(T--)
76     {
77         scanf("%d%d", &n, &m);
78         for(int i=1; i<=n; i++)
79         for(int j=1; j<=n; j++)
80             mat[i][j] = -INF;
81         while(m--)
82         {
83             scanf("%d%d%d", &a, &b, &c);
84             mat[a][b] = mat[b][a] = max(mat[a][b], -c);
85         }
86         printf("Case %d: ", lop++);
87         int ans = KM();
88         if(ans==0) puts("NO");
89         else printf("%d\n", -ans);
90     }
91 }
View Code

 

posted @ 2015-03-30 22:54  无道圣君  阅读(1033)  评论(0编辑  收藏  举报