zoukankan      html  css  js  c++  java
  • [FZYZOJ 1356] 8-3 最小路径覆盖问题

    P1356 -- 8-3 最小路径覆盖问题

    时间限制:1000MS

    内存限制:131072KB

    Description

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

    Input Format

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

    Output Format

    从第1 行开始,每行输出一条路径(行末无空格,有空格你就wa了)。文件的最后一行是最少路径数。

    Sample Input

    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

    Sample Output

    1 4 7 10 11
    2 5 8
    3 6 9
    3

    Hint

    n<=150 m<=6000

    【题解】

    最小路径覆盖可以用二分图匹配/网络流来做。

    具体的就是若从A到B有路径,连A,B+n即可。

    然后匈牙利搞一搞就好了。

     1 #include <stdio.h>
     2 #include <string.h>
     3 using namespace std;
     4 
     5 const int V=500,E=70010;
     6 int n,m;
     7 bool vis[V];
     8 int fa[V],head[V],to[E],next[E],ans=0;
     9 
    10 bool hungry(int u) {
    11     for (int i=head[u];i;i=next[i]) {
    12         if(!vis[to[i]]) {
    13             vis[to[i]]=1;
    14             if(!fa[to[i]]||hungry(fa[to[i]])) {
    15                 fa[to[i]]=u;
    16                 fa[u]=to[i];
    17                 return 1;
    18             }
    19         }
    20     }
    21     return 0;
    22 }
    23 
    24 inline int g() {
    25     int x=0,f=1;char ch=getchar();
    26     while(ch<'0'||ch>'9') {
    27         if(ch=='-') f=-1; 
    28         ch=getchar();
    29     }
    30     while(ch>='0'&&ch<='9') {
    31         x=(x<<1)+(x<<3)+ch-'0';
    32         ch=getchar();
    33     }
    34     return x*f;
    35 }
    36 
    37 int main() {
    38     n=g(),m=g();
    39     for (int i=1,a,b;i<=m;++i) {
    40         a=g(),b=g();
    41         to[i]=b+n;
    42         next[i]=head[a];
    43         head[a]=i;
    44     }
    45     for (int i=1;i<=n;++i) {
    46         if(fa[i]) continue;
    47         memset(vis,0,sizeof(vis));
    48         if(hungry(i)) ++ans;
    49     }
    50     memset(vis,0,sizeof(vis));
    51     for (int i=1;i<=n;++i) {
    52         if(!vis[i]) {
    53             vis[i]=1;
    54             printf("%d",i);
    55             for (int j=fa[i];j;j=fa[j-n]) {
    56                 printf(" %d",j-n);
    57                 vis[j-n]=1;
    58             }
    59             printf("
    ");
    60         }
    61     }
    62     printf("%d
    ",n-ans);
    63     return 0;
    64 }
    View Code
  • 相关阅读:
    LCA问题第二弹
    LCA问题
    树状数组(Binary Indexed Tree,BIT)
    线段树第二弹(区间更新)
    线段树+RMQ问题第二弹
    RMQ问题第一弹
    分治法二(平面最近点对)
    分治法(一)
    带权并查集
    提交一个变量或数组到另一个jsp页面
  • 原文地址:https://www.cnblogs.com/TonyNeal/p/fzyzoj1356.html
Copyright © 2011-2022 走看看