码迷,mamicode.com
首页 > 其他好文 > 详细

最小路径覆盖

时间:2018-03-29 19:10:47      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:ems   href   ==   max   namespace   add   queue   string   pac   

  最小不可交路径覆盖 

题目链接:https://www.luogu.org/problemnew/show/P2764

 题解:

  如何建模?

  把每个点i拆成xi和yi两个点。若i与j间有边,就链接xi与yj,求两个集合的最大匹配。

  证明:

  我们可以把一开始的点每个点看做一条路径。那么每增加一条匹配边,就相当于把两个路径连在一起。连起来的路径越多,则最后路径总数越少。

  怎么求最大匹配?

  网络流。

  怎么输出方案?

  一开始建两层图。比较修改的图与原图,有修改的地方就是连接的路径。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 #include<queue>
  7 #include<bitset>
  8 #define LL long long
  9 #define RI register int
 10 using namespace std;
 11 const int INF = 0x7ffffff ;
 12 const int N = 150 + 10 ;
 13 const int M = 6000 + 10 ;
 14 
 15 inline int read() {
 16     int k = 0 , f = 1 ; char c = getchar() ;
 17     for( ; !isdigit(c) ; c = getchar())
 18       if(c == -) f = -1 ;
 19     for( ; isdigit(c) ; c = getchar())
 20       k = k*10 + c-0 ;
 21     return k*f ;
 22 }
 23 struct Edge {
 24     int to, next, flow ;
 25 }e[(M<<1)+(N<<2)], ee[(M<<1)+(N<<2)] ;
 26 int n, m, s, t ; int head[N<<1], dep[N<<1] ;
 27 bitset<N<<1>vis ;
 28 inline void add_edge(int x,int y,int ff) {
 29     static int cnt = 1 ;
 30     e[++cnt].to = y, e[cnt].next = head[x], e[cnt].flow = ff, head[x] = cnt ;
 31     ee[cnt].to = y, ee[cnt].next = head[x], ee[cnt].flow = ff;
 32     e[++cnt].to = x, e[cnt].next = head[y], e[cnt].flow = 0, head[y] = cnt ;
 33     ee[cnt].to = x, ee[cnt].next = head[y], ee[cnt].flow = 0 ;
 34 }
 35 
 36 inline bool F_bfs() {
 37     memset(dep,0,sizeof(dep)) ;
 38     queue<int>q ; q.push(s) ; dep[s] = 1 ;
 39     while(!q.empty()) {
 40         int x = q.front() ; q.pop() ;
 41         for(int i=head[x];i;i=e[i].next) {
 42             int y = e[i].to ; if(dep[y] || !e[i].flow) continue ;
 43             dep[y] = dep[x] + 1 ; q.push(y) ;
 44         }
 45     }
 46     return dep[t] ;
 47 }
 48 int F_dfs(int x,int minflow) {
 49     if(x == t || minflow <= 0) return minflow ;
 50     int fflow = 0 ;
 51     for(int i=head[x];i;i=e[i].next) {
 52         int y = e[i].to ; if(dep[y] != dep[x]+1) continue ;
 53         int temp = F_dfs(y,min(minflow,e[i].flow)) ;
 54         fflow += temp ; minflow -= temp ;
 55         e[i].flow -= temp ; e[i^1].flow += temp ;        
 56 //        out[x]++, out[y]-- ; printf("x:%d,y:%d\n",x,y) ;
 57         if(!minflow) break ;
 58     }
 59     return fflow ;
 60 }
 61 
 62 void dfs(int x) {
 63     vis[x] = 1 ;
 64     printf("%d ",x) ;
 65     for(int i=head[x];i;i=e[i].next) {
 66         int y = e[i].to ;
 67         if(ee[i].flow && !e[i].flow) {
 68             dfs(y-n) ; break ;
 69         }
 70     }
 71 }
 72 
 73 int main() {
 74 //    freopen("path3.in","r",stdin) ;
 75 //    freopen("path3.out","w",stdout) ;
 76     n = read(), m = read() ;
 77     int x, y, ans = 0 ; s = (n<<1)+1, t = (n<<1)+2 ;
 78     for(int i=1;i<=m;i++) {
 79         x = read(), y = read() ;
 80         add_edge(x,n+y,1) ;
 81     }
 82     for(int i=1;i<=n;i++) add_edge(s,i,1) ;
 83     for(int i=n+1;i<=(n<<1);i++) add_edge(i,t,1) ;
 84     while(F_bfs()) {
 85         ans += F_dfs(s,INF) ;
 86     }
 87 //    printf("ans:%d\n",ans) ;
 88     ans = n-ans ;    
 89     for(int i=1;i<=n;i++) {
 90         if(vis[i]) continue ;
 91         bool flag = 0 ;
 92         for(int j=head[i];j;j=e[j].next) {
 93             if(ee[j].flow && !e[j].flow) {
 94                 flag = 1 ; break ;
 95             }
 96         }
 97         if(flag) {
 98             dfs(i) ; printf("\n") ;
 99         }
100     }
101     printf("%d\n",ans) ;
102     return 0 ;
103 }

 

 最小可交路径覆盖

   把每个点与它可到达的点都按上题连上边,然后就按上题求即可。

 

 魔术球问题

题目链接:https://www.luogu.org/problemnew/show/P2765

  每增加一个球求一遍最小路径覆盖。连完新边之后直接在残量网络上求即可。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<queue> 
 7 #include<bitset>
 8 #define LL long long
 9 #define RI register int
10 using namespace std;
11 const int INF = 0x7ffffff ;
12 const int N = 55 + 2 ;
13 const int M = 1600 + 10 ;
14 
15 inline int read() {
16     int k = 0 , f = 1 ; char c = getchar() ;
17     for( ; !isdigit(c) ; c = getchar())
18       if(c == -) f = -1 ;
19     for( ; isdigit(c) ; c = getchar())
20       k = k*10 + c-0 ;
21     return k*f ;
22 }
23 struct Edge {
24     int to, next, flow ;
25 }e[M*100], ee[M*100] ;
26 int n, s, t ; int head[M<<1], dep[M<<1] ;
27 bitset<M>vis ;
28 inline void add_edge(int x,int y,int ff) {
29     static int cnt = 1 ;
30     ee[++cnt].to = y, ee[cnt].next = head[x], ee[cnt].flow = ff ;
31     e[cnt].to = y, e[cnt].next = head[x], e[cnt].flow = ff, head[x] = cnt ;
32     ee[++cnt].to = x, ee[cnt].next = head[y], ee[cnt].flow = 0 ;
33     e[cnt].to = x, e[cnt].next = head[y], e[cnt].flow = 0, head[y] = cnt ;
34 }
35 
36 inline bool F_bfs() {
37     memset(dep,0,sizeof(dep)) ;
38     queue<int>q ; q.push(s) ; dep[s] = 1 ;
39     while(!q.empty()) {
40         int x = q.front() ; q.pop() ;
41         for(int i=head[x];i;i=e[i].next) {
42             int y = e[i].to ; if(dep[y] || !e[i].flow) continue ;
43             dep[y] = dep[x] + 1 ; q.push(y) ;
44         }
45     }
46     return dep[t] ;
47 }
48 int F_dfs(int x,int minflow) {
49 //    printf("xxx\n") ;
50     if(x == t || minflow <= 0) return minflow ;
51     int fflow = 0 ;
52     for(int i=head[x];i;i=e[i].next) {
53         int y = e[i].to ; if(dep[y] != dep[x]+1 || !e[i].flow) continue ;
54         int temp = F_dfs(y,min(minflow,e[i].flow)) ;
55         fflow += temp ; minflow -= temp ;
56         e[i].flow -= temp ; e[i^1].flow += temp ;
57         if(!minflow) break ;
58     }
59     return fflow ;
60 }
61 void dfs(int x) {
62     printf("%d ",x) ; vis[x] = 1 ;
63     for(int i=head[x];i;i=e[i].next) {
64         if(ee[i].flow && !e[i].flow) {
65             dfs(e[i].to-M) ; break ;
66         }
67     }
68 }
69 
70 inline int sqr(int x) { return x*x ; }
71 int main() {
72 //    freopen("balla.in","r",stdin) ;
73 //    freopen("balla.out","w",stdout) ;
74     n = read() ; int nn = 0 ; s = (M<<1)-10, t = (M<<1)-9 ;
75     int ans = 0, maxx ;
76     while(1) {
77         nn++ ;
78         add_edge(s,nn,1) ; add_edge(nn+M,t,1) ;
79         for(int i=1;i<nn;i++) if(sqr(sqrt(i+nn)) == i+nn) add_edge(i,nn+M,1) ;
80         while(F_bfs()) ans += F_dfs(s,INF) ;
81         if(nn-ans > n) break ;
82         maxx = nn ;
83     }
84     printf("%d\n",maxx) ;
85     for(int x=1;x<=maxx;x++) {
86         if(vis[x]) continue ;
87 //        for(int i=head[x];i;i=e[i].next) {
88 //            if(ee[i].flow && !e[i].flow) {
89         dfs(x) ; printf("\n") ; // break ;
90 //            }
91 //        }
92     }
93     return 0 ;
94 }

 

最小路径覆盖

标签:ems   href   ==   max   namespace   add   queue   string   pac   

原文地址:https://www.cnblogs.com/zub23333/p/8671184.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!