洛谷 P4843 清理雪道 有上下界最小流

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/82792895

题目描述

滑雪场坐落在FJ省西北部的若干座山上。

从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。

你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。

由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。

输入输出格式

输入格式:
输入文件的第一行包含一个整数n (2 <= n <= 100) – 代表滑雪场的地点的数量。

接下来的n行,描述1~n号地点出发的斜坡,第i行的第一个数为mi (0 <= mi < n) ,后面共有mi个整数,由空格隔开,每个整数aij互不相同,代表从地点i下降到地点aij的斜坡。每个地点至少有一个斜坡与之相连。

输出格式:
输出文件的第一行是一个整数k – 直升飞机的最少飞行次数。

输入输出样例

输入样例#1:
8
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0
输出样例#1:
4

分析:
题意是寻找一个DAG的最小边覆盖。
我们首先考虑把边看做点,跑最小点覆盖。因为边很多(可能有 n 2 n^2 条),点可以重复走,即使网络流不T,跑传递闭包也会T。复杂度为 O ( m 3 ) O(m^3)
所以我们考虑直接对原图跑网络流。
建立一个 S S 向每个点连 i n f inf 流量的边(表示可以从任意一点开始),每个点向 T T i n f inf 流量的边(表示可以从任意一点结束)。原图的每条边要至少走一遍,也就是流量为 [ 1 , i n f ) [1,inf)

代码:

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

const int maxn=207;
const int maxe=maxn*maxn*5;
const int inf=0x3f3f3f3f;

using namespace std;

int n,tot,x,cnt,s,t,sum,ans;
int ls[maxn],deg[maxn],dis[maxn];

struct edge{
    int y,w,op,next;
}g[maxe];

queue <int> q;

void add(int x,int y,int w)
{
    g[++cnt]=(edge){y,w,cnt+1,ls[x]};
    ls[x]=cnt;
    g[++cnt]=(edge){x,0,cnt-1,ls[y]};
    ls[y]=cnt;
}

bool bfs()
{   
    memset(dis,inf,sizeof(dis));
    q.push(s);
    dis[s]=0;  
    while (!q.empty())
    {
        int x=q.front();
        q.pop();
        for (int i=ls[x];i>0;i=g[i].next)
        {
            int y=g[i].y;
            if ((g[i].w) && (dis[y]>dis[x]+1))
            {
                dis[y]=dis[x]+1;
                q.push(y);
            }
        }
    }
    return (dis[t]!=inf);
}

int dfs(int x,int maxf)
{
    if ((x==t) || (!maxf)) return maxf;
    int ret=0;
    for (int i=ls[x];i>0;i=g[i].next)
    {
        int y=g[i].y;
        if ((g[i].w) && (dis[y]==dis[x]+1))
        {
            int f=dfs(y,min(maxf-ret,g[i].w));
            if (!f) dis[y]=-1;
            ret+=f;
            g[i].w-=f;
            g[g[i].op].w+=f;
        }
    }
    return ret;
}

int dinic()
{
    int flow=0;
    while (bfs()) 
      flow+=dfs(s,inf);
    return flow;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&tot);
        for (int j=1;j<=tot;j++)
        {
            scanf("%d",&x);
            add(i,x,inf-1);
            deg[i]--;
            deg[x]++;
        }
    }	  
    int S=n+1,T=n+2,SS=n+3,TT=n+4;
    for (int i=1;i<=n;i++)
    {
        add(S,i,inf);
        add(i,T,inf);
    }    
    int nowcnt=cnt;
    add(T,S,inf);
    for (int i=1;i<=n;i++)
    {
        if (deg[i]>0) add(SS,i,deg[i]),sum+=deg[i];
        else if (deg[i]<0) add(i,TT,-deg[i]);
    }
    s=SS,t=TT;
    dinic();
    ans=g[nowcnt+2].w;
    for (int i=nowcnt+1;i<=cnt;i++) g[i].w=0;    
    s=T,t=S;
    ans-=dinic();
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/82792895