hiho# 1394最小路径覆盖 网络流拆点

题目传送门

思路:

  观察到路径上除了终点起点以外的每个点出度和入度都为1,和网络流的拆点很像,所以就把每个点都拆成两个点,若存在一条路径$(u,v)$,则建一条$(u,v+n,1)$的边,然后求出最大流后,每个起点的入度都是0,所以$ans=n-maxflow$。

  注意由于是拆点,所以各种数组都要开两倍空间。

#include<bits/stdc++.h>
#define clr(a,b) memset(a,b,sizeof(a))
using namespace std;

typedef long long ll;

const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int maxn = 510;

struct Edge {
    int to, flow, nxt;
    Edge(){}
    Edge(int to, int nxt, int flow):to(to),nxt(nxt), flow(flow){}
}edge[maxn * maxn * 2];

int head[maxn*2], dep[maxn*2];
int S, T;
int N, n, m, tot;
void init(int n)
{
    N=n;
    for (int i = 0; i <= N; ++i) head[i] = -1;
    tot = 0;
}

void addv(int u, int v, int w, int rw = 0)
{
    edge[tot] = Edge(v, head[u], w); head[u] = tot++;
    edge[tot] = Edge(u, head[v], rw); head[v] = tot++;
}

bool BFS()
{
    for (int i = 0; i <= N; ++i) dep[i] = -1;
    queue<int>q;
    q.push(S);
    dep[S] = 1;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = head[u]; ~i; i = edge[i].nxt)
        {
            
            if (edge[i].flow && dep[edge[i].to] == -1)
            {
                dep[edge[i].to] = dep[u] + 1;
                q.push(edge[i].to);
            }
        }
    }
    return dep[T] < 0 ? 0 : 1;
}

int DFS(int u, int f)
{
    if (u == T || f == 0) return f;
    int w, used = 0;
    for (int i = head[u]; ~i; i = edge[i].nxt)
    {
        if (edge[i].flow && dep[edge[i].to] == dep[u] + 1)
        {
            w = DFS(edge[i].to, min(f - used, edge[i].flow));
            edge[i].flow -= w;
            edge[i ^ 1].flow += w;
            used += w;
            if (used == f) return f;
        }
    }
    if (!used) dep[u] = -1;
    return used;
}

int Dicnic()
{
    int ans = 0;
    while (BFS())
    {
        ans += DFS(S, INF);
    }
    return ans;
}

int main(){
    cin>>n>>m;
    T=2*n+1;
    init(T);
    S=0;
    while(m--){
        int u,v;
        scanf("%d%d",&u,&v);
        addv(u,v+n,1);
    }
    for(int i=1;i<=n;i++){
        addv(S,i,1);
        addv(i+n,T,1);
    }
    int ans=n-Dicnic();
    printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/mountaink/p/10670781.html