AC日记——最小路径覆盖问题 洛谷 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

思路:

  网络流24题之一;

  还是那条性质,求最小割;

  每条有向边的u,v加边都是u,v+n;

  求出最大流,ans=n-最大流;

  然后,我们在求最大流的时候把匹配的点和边做标记以输出路径;

来,上代码:

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

#define INF 0x7ffffff

using namespace std;

struct EdgeType {
    int to,next,flow;
};
struct EdgeType edge[24005];

int if_z,n,m,cnt=1,head[505],s=0,t=504;
int deep[505],next[505],ans;

bool if_[505];

char Cget;

inline void in(int &now)
{
    now=0,if_z=1,Cget=getchar();
    while(Cget>'9'||Cget<'0')
    {
        if(Cget=='-') if_z=-1;
        Cget=getchar();
    }
    while(Cget>='0'&&Cget<='9')
    {
        now=now*10+Cget-'0';
        Cget=getchar();
    }
    now*=if_z;
}

inline void edge_add(int u,int v,int w)
{
    edge[++cnt].to=v,edge[cnt].flow=w,edge[cnt].next=head[u],head[u]=cnt;
    edge[++cnt].to=u,edge[cnt].flow=0,edge[cnt].next=head[v],head[v]=cnt;
}

bool BFS()
{
    queue<int>que;
    memset(deep,-1,sizeof(deep));
    que.push(s),deep[s]=0;
    while(!que.empty())
    {
        int pos=que.front();
        for(int i=head[pos];i;i=edge[i].next)
        {
            if(deep[edge[i].to]<0&&edge[i].flow>0)
            {
                deep[edge[i].to]=deep[pos]+1;
                if(edge[i].to==t) return true;
                que.push(edge[i].to);
            }
        }
        que.pop();
    }
    return false;
}

int flowing(int now,int flow)
{
    if(now==t||flow==0) return flow;
    int oldflow=0;
    for(int i=head[now];i;i=edge[i].next)
    {
        if(deep[edge[i].to]!=deep[now]+1||edge[i].flow==0) continue;
        int pos=flowing(edge[i].to,min(flow,edge[i].flow));
        if(pos>0)
        {
            next[now]=edge[i].to;
            if(edge[i].to>n) if_[edge[i].to-n]=true;
        }
        flow-=pos;
        oldflow+=pos;
        edge[i].flow-=pos;
        edge[i^1].flow+=pos;
        if(flow==0) return oldflow;
    }
    return oldflow;
}

void dinic()
{
    while(BFS()) ans-=flowing(s,INF);
}

int main()
{
    in(n),in(m);int u,v;ans=n;
    for(int i=1;i<=m;i++)
    {
        in(u),in(v);
        edge_add(u,v+n,INF);
    }
    for(int i=1;i<=n;i++)
    {
        edge_add(s,i,1);
        edge_add(i+n,t,1);
    }
    dinic();
    for(int i=1;i<=n;i++)
    {
        if(if_[i]) continue;
        int pos=i;
        printf("%d",pos);
        while(next[pos])
        {
            if(next[pos]>n) next[pos]-=n;
            printf(" %d",next[pos]);
            pos=next[pos];
        }
        printf("
");
    }
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6440057.html