【bzoj2502】【清理雪道】【最小流】

来源:互联网 发布:centos 网卡绑定mac 编辑:程序博客网 时间:2024/05/19 17:27

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

题解:

裸的最小流

具体做法就是

1.新建源汇S,T,按有上下界的方法建图.

2.做一次S->T的最大流.

3.原图中的汇点t向原图中的源点s连一条inf的边.

4.再做一次S->T的最大流就是答案.

代码:

#include<iostream>#include<cstdio>#include<cstring>#define N 200#define M 20000 #define inf 210000000using namespace std;int x,y,S,T,n,s,t,num,d[N],point[N],next[M<<1],cnt=1;int cur[N],pre[N],gap[N],dis[N],ans;struct use{  int st,en,v;}e[M<<1];int read(){  int x(0);char ch=getchar();  while (ch<'0'||ch>'9') ch=getchar();  while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();  return x;}void add(int x,int y,int v){  next[++cnt]=point[x];point[x]=cnt;  e[cnt].st=x;e[cnt].en=y;e[cnt].v=v;  next[++cnt]=point[y];point[y]=cnt;  e[cnt].st=y;e[cnt].en=x;e[cnt].v=0;}int isap(int ss,int tt){  int mn,u=ss,i,ans=0;  gap[0]=tt;  for (int i=1;i<=tt;i++) gap[i]=0;  for (int i=1;i<=tt;i++) dis[i]=0;  for (int i=1;i<=tt;i++) cur[i]=point[i];  while (dis[ss]<tt){    bool f=false;    for (i=cur[u];i;i=next[i])      if (e[i].v&&dis[e[i].en]+1==dis[u]){f=true;cur[u]=i;break;}    if (f){      pre[u=e[i].en]=i;      if (u==tt){        mn=inf;        for (int i=tt;i!=ss;i=e[pre[i]].st) mn=min(mn,e[pre[i]].v);        ans+=mn;        for (int i=tt;i!=ss;i=e[pre[i]].st) e[pre[i]].v-=mn,e[pre[i]^1].v+=mn;        u=ss;      }    }      else{      gap[dis[u]]--;if (!gap[dis[u]]) return ans;      for (mn=tt,i=point[u];i;i=next[i]) if (e[i].v)mn=min(mn,dis[e[i].en]);      gap[dis[u]=mn+1]++;cur[u]=point[u];if (u!=ss) u=e[pre[u]].st;    }  }   return ans;} int main(){   n=read();s=n+1;t=s+1;S=t+1;T=S+1;   for (int i=1;i<=n;i++){      num=read();      for (int j=1;j<=num;j++){        x=read();        add(i,x,inf);        d[i]--;d[x]++;      }   }       for (int i=1;i<=n;i++) add(s,i,inf),add(i,t,inf);   for (int i=1;i<=n;i++){     if (d[i]>0) add(S,i,d[i]);     else if (d[i]<0) add(i,T,-d[i]);   }   ans=isap(S,T);   add(t,s,inf);   ans=isap(S,T);   cout<<ans<<endl;}


0 0