首页 > 其他 > 详细

有向环覆盖问题

时间:2015-03-31 00:24:21      阅读:442      评论:0      收藏:0      [点我收藏+]

转载自这里

 

  给你一个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 }

 

有向环覆盖问题

原文:http://www.cnblogs.com/khan724/p/4379477.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!