1. 程式人生 > >LiberOJ #6002. 「網絡流 24 題」最小路徑覆蓋

LiberOJ #6002. 「網絡流 24 題」最小路徑覆蓋

技術分享 記錄 -m lock onclick stat blog 自己 給定

#6002. 「網絡流 24 題」最小路徑覆蓋

內存限制:256 MiB時間限制:1000 ms標準輸入輸出 題目類型:傳統評測方式:Special Judge 上傳者: 匿名 提交提交記錄統計討論測試數據

題目描述

給定有向圖 G=(V,E) G = (V, E)G=(V,E)。設 P PP 是 G GG 的一個簡單路(頂點不相交)的集合。如果 V VV 中每個頂點恰好在 P PP 的一條路上,則稱 P PP 是 G GG 的一個路徑覆蓋。P PP 中路徑可以從 V VV 的任何一個頂點開始,長度也是任意的,特別地,可以為 0 00。G GG 的最小路徑覆蓋是 G GG 的所含路徑條數最少的路徑覆蓋。

設計一個有效算法求一個有向無環圖 G GG 的最小路徑覆蓋。

輸入格式

1 11 行有 2 22 個正整數 n nn 和 m mm。n nn 是給定有向無環圖 G GG 的頂點數,m mm 是 G GG 的邊數。
接下來的 m mm 行,每行有 2 22 個正整數 u uu 和 v vv,表示一條有向邊 (i,j) (i, j)(i,j)。

輸出格式

從第 1 11 行開始,每行輸出一條路徑。
文件的最後一行是最少路徑數。

樣例

樣例輸入

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 4 7 10 11
2 5 8
3 6 9
3

數據範圍與提示

1≤n≤200,1≤m≤6000 1 \leq n \leq 200, 1 \leq m \leq 60001n200,1m6000

題目鏈接:https://loj.ac/problem/6002

題意:輸出一個有向圖的點不重復的最小路徑覆蓋。

思路:點不重復的最小路徑覆蓋。最初始每個點都最為自己一個獨立的路徑,如果有一個匹配,那麽路徑-1,所以最小路徑覆蓋,點不重復的情況就是求最大匹配。

點可重復的最小路徑覆蓋也是使用匹配,只不過,需要增加一些邊,如果u可以到達匹配,則增加<u,v>,這樣就會跳過一些中間點。

代碼:

技術分享
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int maxn=300,maxm=1e5+1000,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=1e18+7;
int n,m;
vector<int>G[maxn];
bool used[maxn];
int cx[maxn],cy[maxn];
bool vis[maxn];
void pprintf(int u)
{
    vis[u]=true;
    if(cx[u]<0)
    {
        printf("\n");
        return ;
    }
    printf(" %d",cx[u]);
    pprintf(cx[u]);
}
bool dfs(int u)
{
    for(int i=0; i<G[u].size(); i++)
    {
        int v=G[u][i];
        if(used[v]) continue;
        used[v]=true;
        if(cy[v]<0||dfs(cy[v]))
        {
            cy[v]=u,cx[u]=v;
            return true;
        }
    }
    return false;
}
int solve()
{
    int res=0;
    memset(cy,-1,sizeof(cy));
    memset(cx,-1,sizeof(cx));
    for(int i=1; i<=n; i++)
    {
        memset(used,false,sizeof(used));
        res+=dfs(i);
    }
    memset(vis,false,sizeof(vis));
    for(int i=1; i<=n; i++)
    {
        if(!vis[i])
        {
            printf("%d",i);
            pprintf(i);
        }
    }
    printf("%d\n",n-res);
}
int main()
{
    scanf("%d%d",&n,&m);
    int u,v;
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
    }
    solve();
    return 0;
}
最小路徑覆蓋

LiberOJ #6002. 「網絡流 24 題」最小路徑覆蓋