zoukankan      html  css  js  c++  java
  • [网络流二十四题]最小路径覆盖问题

    最小路径覆盖

    题目描述

    一个有向无回路的图G=(V,E)的一个路径覆盖是一个其结点不相交的路径集合P,图中的每一个结点仅包含于P中的一条路径。路径可从任意结点开始和结束,且长度也为任意值,包括0。请写出一个有效算法,找出一个包含尽可能少的路径的路径覆盖图中的所有点。
      例如下图至少用两条路径覆盖,路径可以是:1-5-3,2-4。

    输入

    输入文件第一行为n(n≤4000),表示图G的顶点个数,从第二行开始每行有两个数u,v表示存在边(u,v)。

    输出

    输出文件的第一行为所求的最少的路径覆盖数k。第二行至第k+1行为每条路径上以0结尾的顶点序列。

    样例输入

    5
    1 2
    1 5
    2 3
    2 4
    5 3
    

    样例输出

    2
    1 5 3 0
    2 4 0


    这题自己的代码调了一晚上+早上一节课莫名其妙调不过去--弃了 抄了同学的代码
    这个问题乍一看似乎与网络流没有什么关系,一开始我想到的似乎是最小割
    后来经过dalao们指导,知道了是把DAG中点每一个点拆成一个出点一个入点,然后重构成二分图。
    因为最小路径覆盖中的每一个路径上点(非起点终点)的出度与入度都是1
    所以就能用二分图最大匹配来求解最小路径覆盖
    答案是n - 二分图最大匹配数
    这里的解法用的是Dinic,对于二分图出点集合中的每一个点,连一条从S出发的边,对于每个出点集合中的点连一条边到T,跑一遍最大流就好了
    下面是同学的代码:
     1 #include<iostream>
     2 #include<cmath>
     3 #include<cstdio> 
     4 #include<cstdlib>
     5 #include<cstring>
     6 #include<queue>
     7 #include<algorithm>
     8 #define inf 0x7fffffff 
     9 using namespace std;
    10 struct edge {
    11     int to, cap, next;
    12 }e[400005];
    13 int head[8005], iter[8005], lev[8005], way[8005];
    14 bool mk[8005];
    15 int st, en, c, cnt = 1, s, t, n, m;
    16 inline void ins(int x, int y, int cp)
    17 {
    18     cnt++; e[cnt].to = y; e[cnt].next = head[x]; head[x] = cnt; e[cnt].cap = cp;
    19     cnt++; e[cnt].to = x; e[cnt].next = head[y]; head[y] = cnt; e[cnt].cap = 0;
    20 }
    21 void bfs()
    22 {
    23     memset(lev, -1, sizeof(lev));
    24     queue<int>q;
    25     lev[0] = 0; q.push(0);
    26     while (!q.empty()) {
    27         int v = q.front(); q.pop();
    28         for (int i = head[v]; i; i = e[i].next) {
    29             edge &ed = e[i];
    30             if (ed.cap>0 && lev[ed.to]<0) {
    31                 lev[ed.to] = lev[v] + 1; q.push(ed.to);
    32             }
    33         }
    34     }
    35 }
    36 int dfs(int u, int f)
    37 {
    38     int used = 0;
    39     if (u == t) return f;
    40     for (int i = head[u]; i; i = e[i].next)
    41     {
    42         edge &ed = e[i];
    43         if (ed.cap>0 && lev[u]<lev[ed.to]) {
    44             int w = dfs(ed.to, min(f - used, ed.cap));
    45             if (w>0) {
    46                 if (ed.to - n>0) { way[u] = ed.to - n; mk[ed.to - n] = true; }
    47                 ed.cap -= w; e[i ^ 1].cap += w; used += w;
    48                 if (used == f) return f;
    49             }
    50         }
    51     }
    52     if (!used) lev[u] = -1;
    53     return used;
    54 }
    55 int dinic()
    56 {
    57     int fl = 0;
    58     while (1)
    59     {
    60         bfs(); if (lev[t]<0) return fl;
    61         int d = dfs(0, inf); if (d>0) fl += d;
    62     }
    63 }
    64 int main()
    65 {
    66     scanf("%d", &n); s = 0; t = 2 * n + 1;
    67     while (scanf("%d%d", &st, &en) == 2) ins(st, en + n, 1);
    68     for (int i = 1; i <= n; i++) ins(0, i, 1); for (int i = 1; i <= n; i++)ins(i + n, 2 * n + 1, 1);
    69     printf("%d
    ", n - dinic());
    70     for (int i = 1; i <= n; i++) {
    71         if (mk[i]) continue;
    72         for (int j = i; j; j = way[j]) printf("%d ", j);
    73         printf("0
    ");
    74     }
    75     return 0;
    76 }

                下面是自己的(恬不知耻的放上来)不知道哪里出BUG了QAQQ

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<queue>
      4 
      5 const int Maxv = 8005, INF = 0x6ffffff; 
      6 int Head[Maxv], Next[Maxv << 1], V[Maxv << 1], W[Maxv << 1], Way[Maxv], Dep[Maxv], cnt = 1, n, s, t; 
      7 bool Mk[Maxv]; 
      8 
      9 void Add(int u, int v, int w){
     10     cnt++; 
     11     Next[cnt] = Head[u]; 
     12     V[cnt] = v; 
     13     W[cnt] = w; 
     14     Head[u] = cnt; 
     15 }
     16 
     17 void Add_Edge(int u, int v, int w){
     18     Add(u, v, w); 
     19     Add(v, u, 0); 
     20 }
     21 
     22 void BFS(){
     23     std::queue<int> Q; 
     24     memset(Dep, -1, sizeof(Dep)); 
     25     Dep[s] = 0; 
     26     Q.push(s); 
     27     while (!Q.empty()) { 
     28         int u = Q.front(); 
     29         Q.pop();
     30         for (int i = Head[u]; i; i = Next[i]) {
     31             if (Dep[V[i]] < 0 && W[V[i]] > 0) {  //没有增广过且剩余容量大于0 
     32                 Dep[V[i]] = Dep[u] + 1; 
     33                 Q.push(V[i]); 
     34             }
     35         }
     36     }
     37 }
     38 
     39 int DFS(int u, int dist){
     40     int flow = 0; 
     41     if (u == t) {
     42         return dist; 
     43     }
     44     for (int i = Head[u]; i; i = Next[i]) {
     45         if (Dep[V[i]] == Dep[u] + 1 && W[i] > 0) {
     46             int w = DFS(V[i], std::min(dist - flow, W[i])); 
     47             if (w > 0) {
     48                 if (V[i] - n > 0) {
     49                     Way[u] = V[i] - n; 
     50                     Mk[V[i] - n] = true; 
     51                 }
     52                 W[i] -= w; 
     53                 W[i ^ 1] += w; 
     54                 flow += w; 
     55                 if (flow == dist) {
     56                     return dist; 
     57                 }
     58             }
     59         }
     60     }
     61     if (!flow) {
     62         Dep[u] = -1; 
     63     }
     64     return flow; 
     65 }
     66 
     67 int Dinic() {
     68     int Ans = 0; 
     69     while (1) {
     70         BFS(); 
     71         if (Dep[t] < 0) {
     72             return Ans; 
     73         }
     74         int d = DFS(0, INF); 
     75         if (d > 0) {
     76             Ans += d;  
     77         }
     78     }
     79 }
     80 
     81 int main(){
     82     int st, ed; 
     83     scanf("%d", &n); 
     84     s = 0;
     85     t = 2 * n + 1; 
     86     while (scanf("%d%d", &st, &ed) == 2) {
     87         Add_Edge(st, ed, 1); 
     88     }
     89     for (int i = 1; i <= n; i++) {
     90         Add_Edge(s, i, 1);
     91     }
     92     for (int i = 1; i <= n; i++) {
     93         Add_Edge(i + n, t, 1);
     94     }            //连入超级S和超级T, 把DAG重构成二分图
     95     printf("%d
    ", n - Dinic());    
     96     for (int i = 1; i <= n; i++) {
     97         if (Mk[i]) {
     98             continue; 
     99         }
    100         for (int j = 1; j; j = Way[j]) {
    101             printf("%d ", j); 
    102         }
    103         printf("0
    "); 
    104     }
    105     return 0; 
    106 }
     
  • 相关阅读:
    jquery1.9之学习笔记
    ERROR: Removing 'hello': Device or resource busy
    windows虚拟机性能调整
    kvm虚拟机控制台登录配置
    KVM虚拟机的管理
    window kvm 虚拟机的创建
    kvm虚拟化环境的搭建
    C实现哈希表
    哲学家就餐问题 C语言实现
    Linux面试题
  • 原文地址:https://www.cnblogs.com/GldHkkowo/p/8872273.html
Copyright © 2011-2022 走看看