洛谷 P2764 LibreOJ 6002 最小路径覆盖问题

简介: 题目描述 «问题描述: 给定有向图G=(V,E)。设P 是G 的一个简单路(顶点不相交)的集合。如果V 中每个顶点恰好在P 的一条路上,则称P是G 的一个路径覆盖。P 中路径可以从V 的任何一个顶点开始,长度也是任意的,特别地,可以为0。

题目描述

«问题描述:

给定有向图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

吐槽

  这题洛谷居然没有SPJ,大家来这里交吧。要在洛谷上AC就必须像造数据的人那样——用链式前向星反着加边,然后跑dinic。我的匈牙利明明能得出一个最优解,洛谷就是给我爆零,大坏蛋。下面的代码能出解不能在洛谷AC,大家别想复制了。因为一些事,心情不爽,我也不太想在洛谷上交dinic了,抄了个题解混一波通过数。

解题思路

  裸题。u到v有连边,那么就在二分图里把男u号与女v号牵线,然后跑二分图最大匹配,得到匹配数k,答案最后那行就是$n-k$了。至于前面输出路径,直接顺着二分图走即可,我感觉我的这部分代码挺好懂的(逃)

我的源代码

#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

int n,m;
struct men{
    int w;//对象
    vector<int> lover;
}man[156];
int woman[156]={0};
inline void add(int u,int v)
{
    man[u].lover.push_back(v);
}

bool vis[156];
bool dfs(int u)
{
    int sz=man[u].lover.size();
    for(int i=0;i<sz;i++)
    {
        int v=man[u].lover[i];
        if(vis[v])continue;
        vis[v]=1;
        if(!woman[v]||dfs(woman[v]))
        {
            woman[v]=u;
            man[u].w=v;
            return 1;
        }
    }
    return 0;
}
void print(int i)
{
    if(i==0||vis[i])
    {
        printf("\n");
        return;
    }
    vis[i]=1;
    printf("%d ",i);
    print(man[i].w);
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(man,0,sizeof(man));
    for(int i=1,u,v;i<=m;i++)
        scanf("%d%d",&u,&v),add(u,v);
    int ans=0;
    for(int i=1;i<=n;i++) reverse(man[i].lover.begin(),man[i].lover.end());
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(dfs(i))ans++;
    }
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
    {
        if(!vis[i]) print(i);
    }
    printf("%d\n",n-ans);
    return 0;
}

洛谷题解代码

#include <stdio.h>
#include <cstring>
#include <queue>
#define maxn 20000
#define fill(x,y) memset(x,y,sizeof(x))
#define min(x,y) x<y?x:y
#define INF 0x7f7f7f7f
using namespace std;
struct edge{int y,w,rev,next;}e[maxn];
int ls[maxn],n,m,maxE=0,vis[maxn],state[maxn];
int add(int x,int y,int w)//将边加入
{
    e[++maxE]=(edge){y,w,maxE+1,ls[x]};
    ls[x]=maxE;
    e[++maxE]=(edge){x,0,maxE-1,ls[y]};
    ls[y]=maxE;
    return 0;
}
int bfs(int x)//暴力搜索
{
    queue <int> t;
    t.push(x);
    fill(state,63);
    state[x]=0;
    while (!t.empty())
    {
        int tt=t.front();t.pop();
        for (int i=ls[tt];i;i=e[i].next)
        {
            if (e[i].w>0&&state[tt]+1<state[e[i].y])
            {
                state[e[i].y]=state[tt]+1;
                t.push(e[i].y);
                if (e[i].y==n+n+1)
                    return true;
            }
        }
    }
    return false;
}
int find(int x,int mn)//dinic
{
    if (x==n+n+1) return mn;
    for (int i=ls[x];i;i=e[i].next)
        if (state[x]+1==state[e[i].y]&&e[i].w>0)
        {
            int d=find(e[i].y,min(mn,e[i].w));
            if (d>0)
            {
                e[i].w-=d;
                e[e[i].rev].w+=d;
                vis[x]=e[i].y;//记录路径
                return d;
            }
        }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y+n,1);
    }
    for (int i=1;i<=n;i++)//连边
    {
        add(0,i,1);
        add(n+i,n+n+1,1);
    }
    int ans=0;

    while (bfs(0))
    {
        int d=find(0,INF);//最大流
        ans+=d;
    }

    for (int i=1;i<=n;i++)
    {
        if (vis[i]!=0)//输出路径
        {
            int t=i;
            do
            {
                if (t>n) t-=n;
                printf("%d ",t);
                int x=vis[t];
                vis[t]=0;
                t=x;
            }
            while (t!=0);
            printf("\n");
        }
    }
    printf("%d\n",n-ans);//最小路径覆盖=总点数-最大匹配 
    return 0;
}

 

目录
相关文章
|
9月前
|
索引
洛谷P1231 教辅的组成
洛谷P1231 教辅的组成
洛谷1102 A-B 暴力法
判断第 i 个数和 i 之后的每一个数的绝对值是否等于目标结果
|
12月前
|
存储 人工智能 BI
AcWing - 寒假每日一题2023(DAY 11——DAY 15)
AcWing - 寒假每日一题2023(DAY 11——DAY 15)
|
12月前
|
机器学习/深度学习 测试技术
AcWing - 寒假每日一题2023(DAY 16——DAY 20)
AcWing - 寒假每日一题2023(DAY 16——DAY 20)
|
机器学习/深度学习 编译器
【AcWing周赛】AcWing第85场周赛
目录 &lt;一&gt;Acwing 4791. 死或生 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 &lt;二&gt;Acwing 4792. 最大价值 一、题目 1、原题链接 2、题目描述 二、解题报告: 1、思路分析 2、时间复杂度 3、代码详解 &lt;三&gt;Acwing 4793. 危险程度 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 &lt;四&gt; 知识风暴 1、排序不等式 2、贪心法 3、数据范围 4、并查集 基本操作
63 0
|
机器学习/深度学习 人工智能 安全
【AcWing周赛】AcWing第86场周赛
目录 <一>AcWing 4794. 健身 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 <二>AcWing 4795. 安全区域 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解 <三>AcWing 4796. 删除序列 一、题目 1、原题链接 2、题目描述 二、解题报告 1、思路分析 2、时间复杂度 3、代码详解
59 0
洛谷 P1469 找筷子
题目描述 经过一段时间的紧张筹备,电脑小组的“RP餐厅”终于开业了,这天,经理LXC接到了一个定餐大单,可把大家乐坏了!员工们齐心协力按要求准备好了套餐正准备派送时,突然碰到一个棘手的问题,筷子!CX小朋友找出了餐厅中所有的筷子,但遗憾的是这些筷子长短不一,而我们都知道筷子需要长度一样的才能组成一双,更麻烦的是CX找出来的这些筷子数量为奇数,但是巧合的是,这些筷子中只有一只筷子是落单的,其余都成双,善良的你,可以帮CX找出这只落单的筷子的长度吗? 输入输出格式 输入格式:   第一行读入一个数N,它代表CX找到的筷子的根数。
1189 0
|
算法
洛谷 P1816 忠诚
题目描述 老管家是一个聪明能干的人。他为财主工作了整整10年,财主为了让自已账目更加清楚。要求管家每天记k次账,由于管家聪明能干,因而管家总是让财主十分满意。但是由于一些人的挑拨,财主还是对管家产生了怀疑。
1142 0