清理雪道(bzoj 2502)

Description

       滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
 

Input

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

Output

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

Sample Input

8
1 3
1 7
2 4 5
1 8
1 8
0
2 6 5
0

Sample Output

4
/*
    有源汇上下界最小流。
    设原来的源汇点为SS、TT,超级源汇点为S、T。 
    先按照可行流建立模型,然后由TT向SS连一条inf的边,跑可行流。
    那么现在可行流会聚积在TT到SS的边上,我们需要从TT往SS反流一遍最大流,使正的流量尽量小。 
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#define N 110
#define M 21000
#define inf 1000000000
using namespace std;
int head[N],dis[N],s[N],n,cnt=1,SS,TT,S,T;
struct node{int v,f,pre;}e[M];
queue<int> q;
void add(int u,int v,int f){
    e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt;
    e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt;
}
bool bfs(){
    memset(dis,-1,sizeof(dis));
    q.push(S);dis[S]=0;
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=head[u];i;i=e[i].pre)
            if(e[i].f&&dis[e[i].v]==-1){
                dis[e[i].v]=dis[u]+1;
                q.push(e[i].v);
            }
    }
    return dis[T]!=-1;
}
int dinic(int x,int f){
    int rest=f;
    if(x==T) return f;
    for(int i=head[x];i;i=e[i].pre){
        if(!e[i].f||dis[e[i].v]!=dis[x]+1) continue;
        int t=dinic(e[i].v,min(rest,e[i].f));
        e[i].f-=t;e[i^1].f+=t;rest-=t;
    }
    if(rest==f) dis[x]=-1;
    return f-rest;
}
int main(){
    scanf("%d",&n);SS=0;TT=n+1;S=n+2,T=n+3;
    for(int i=1;i<=n;i++){
        int m,x;scanf("%d",&m);
        for(int j=1;j<=m;j++){
            scanf("%d",&x);
            s[i]++;s[x]--;add(i,x,inf);
        }
    }
    for(int i=1;i<=n;i++){
        if(s[i]>0) add(i,T,s[i]);
        if(s[i]<0) add(S,i,-s[i]);
        add(SS,i,inf);
        add(i,TT,inf);
    }
    add(TT,SS,inf);
    while(bfs()) dinic(S,inf);
    head[SS]=e[head[SS]].pre;
    head[TT]=e[head[TT]].pre;
    for(int i=head[S];i;i=e[i].pre)
        e[i].f=e[i^1].f=0;
    for(int i=head[T];i;i=e[i].pre)
        e[i].f=e[i^1].f=0;
    int sum=e[cnt].f;
    add(S,TT,inf);add(SS,T,inf);
    while(bfs()) sum-=dinic(S,inf);
    printf("%d",sum);
    return 0;
}

 

posted @ 2017-03-27 22:14  karles~  阅读(228)  评论(0编辑  收藏  举报