zoukankan      html  css  js  c++  java
  • 洛谷 P2764 最小路径覆盖问题【最大流+拆点+路径输出】

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

    题目描述

    «问题描述:

    给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是G 的所含路径条数最少的路径覆盖。设计一个有效算法求一个有向无环图G 的最小路径覆盖。提示:设V={1,2,.... ,n},构造网络G1=(V1,E1)如下:

    每条边的容量均为1。求网络G1的( 0 x , 0 y )最大流。

    «编程任务:

    对于给定的给定有向无环图G,编程找出G的一个最小路径覆盖。

    输入输出格式

    输入格式:

    件第1 行有2个正整数n和m。n是给定有向无环图G 的顶点数,m是G 的边数。接下来的m行,每行有2 个正整数i和j,表示一条有向边(i,j)。

    输出格式:

    从第1 行开始,每行输出一条路径。文件的最后一行是最少路径数。

    输入输出样例

    输入样例#1:
    11 12
    1 2
    1 3
    1 4
    2 5
    3 6
    4 7
    5 8
    6 9
    7 10
    8 11
    9 11
    10 11
    输出样例#1:
    1 4 7 10 11
    2 5 8
    3 6 9
    3

    说明

    1<=n<=150,1<=m<=6000

    由@zhouyonglong提供SPJ

     

    题解:

      最小路径覆盖问题。答案就是N-最大二分匹配(证明略,感觉hihoCoder上讲的很详细,推荐看)。

      将每个点拆点分成AB两部分,做最大二分匹配。然后源点到A部的点连边,边权为1;B部点到汇点连边,边权为1,跑最大流......

      关于路径输出问题,可以从汇点开始找残余容量为0的点作为起始点递归输出路径...

    代码:

      1 #include <cstdio>
      2 #include <vector>
      3 #include <algorithm>
      4 #include <queue>
      5 #include <cstring>
      6 using namespace std;
      7 const int N = 250*2+5;
      8 const int M = 6000*2+5;
      9 const int inf = 1e9;
     10 int n, m, S, T;
     11 int dep[N], cur[N];
     12 int head[N];
     13 struct Edge{
     14     int v, c, nex;
     15     Edge(int _v=0,int _c=0,int _nex=0):v(_v),c(_c),nex(_nex){}
     16 }E[M];
     17 
     18 int cnt;
     19 void add(int u, int v, int c){
     20     E[cnt].v = v;
     21     E[cnt].c = c;
     22     E[cnt].nex = head[u];
     23     head[u] = cnt++;
     24 }
     25 
     26 bool bfs() {
     27     queue<int> q;
     28     memset(dep, -1, sizeof(dep));
     29     q.push(S); dep[S] = 0;
     30     while(!q.empty()) {
     31         int u = q.front(); q.pop();
     32         for(int i = head[u]; ~i; i = E[i].nex) {
     33             int v = E[i].v;
     34             if(E[i].c && dep[v] == -1) {
     35                 dep[v] = dep[u] + 1;
     36                 q.push(v);
     37             }
     38         }
     39     }
     40     return dep[T] != -1;
     41 }
     42 int dfs(int u, int flow) {
     43     if(u == T) return flow;
     44     int w, used=0;
     45     for(int i = head[u]; ~i; i = E[i].nex) {
     46         int v = E[i].v;
     47         if(dep[v] == dep[u] + 1) {
     48             w = flow - used;
     49             w = dfs(v, min(w, E[i].c));
     50             E[i].c -= w;  E[i^1].c += w;
     51             if(v) cur[u] = i;
     52             used += w;
     53             if(used == flow) return flow;
     54         }
     55     }
     56     if(!used) dep[u] = -1;
     57     return used;
     58 }
     59 int dinic() {
     60     int ans = 0;
     61     while(bfs()) {
     62         for(int i = 0; i <= T;i++)
     63             cur[i] = head[i];
     64         ans += dfs(S, inf);
     65     }
     66     return ans;
     67 }
     68 void print(int x, int &f) {
     69     if(x <= S) return;
     70     if(f == 1) f = 0;
     71     else printf(" ");
     72     printf("%d", x);
     73 
     74     for(int i = head[x]; ~i; i = E[i].nex) {
     75         if(!E[i].c){
     76             print(E[i].v - n, f);
     77         }
     78     }
     79 }
     80 int main() {
     81     int i, j, u, v;
     82     scanf("%d%d", &n, &m);
     83     memset(head, -1, sizeof(head));
     84     cnt = 0;
     85     S = 0; T = 2*n+1;
     86     for(i = 0; i < m; ++i) {
     87         scanf("%d%d", &u, &v);
     88         add(u, v+n, 1); add(v+n, u, 0);
     89     }
     90     for(i = 1; i <= n; ++i) add(S,i,1),add(i,S,0);
     91     for(i = 1; i <= n; ++i) add(i+n,T,1),add(T,i+n,0);
     92 
     93     int ans = dinic();
     94 
     95     for(i = head[T]; ~i; i = E[i].nex) {
     96         if(!E[i].c) {
     97             int f = 1;
     98             print(E[i].v - n, f);
     99             puts("");
    100         }
    101     }
    102     printf("%d
    ", n-ans);
    103     return 0;
    104 }
    105 
    106 /*
    107 7 7
    108 1 2
    109 1 3
    110 2 4
    111 3 4
    112 4 5
    113 4 6
    114 5 7
    115 */
    View Code
  • 相关阅读:
    42.纯 CSS 创作一个均衡器 loader 动画
    41.纯 CSS 绘制一支栩栩如生的铅笔
    1.如何在Cloud Studio上执行Python代码?
    2.每个 HTML 文件里开头都有个<!DOCTYPE>
    39.纯 CSS 创作一个表达怀念童年心情的条纹彩虹心特效
    LOJ #2127. 「HAOI2015」按位或 min-max容斥+FWT
    HDU
    LOJ #3044. 「ZJOI2019」Minimax 搜索 动态DP+概率
    LOJ #3043. 「ZJOI2019」线段树 线段树+分类讨论
    Comet OJ
  • 原文地址:https://www.cnblogs.com/GraceSkyer/p/9017019.html
Copyright © 2011-2022 走看看