zoukankan      html  css  js  c++  java
  • 最小路径覆盖

      最小不可交路径覆盖 

    题目链接: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
    ",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
    ",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("
    ") ;
     99         }
    100     }
    101     printf("%d
    ",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
    ") ;
    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
    ",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("
    ") ; // break ;
    90 //            }
    91 //        }
    92     }
    93     return 0 ;
    94 }
  • 相关阅读:
    学习笔记10-用户和组
    学习笔记9-环境变量
    学习笔记8-检测磁盘空间
    学习笔记7-监测程序
    学习笔记6-权限管理
    【数学】矩阵的逆
    【数学】矩阵
    【数学】Polya定理
    【图论】必经点和必经边
    【图论】点双连通分量
  • 原文地址:https://www.cnblogs.com/zub23333/p/8671184.html
Copyright © 2011-2022 走看看