清理雪道
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
HINT
Source
2011福建集训
哇还真有最小流这种操作……
思路:
考虑网络流,按题意建图。
由于技术原因,显然需要一对源和汇。
发现流量至少为1,于是这是个有源汇上下界网络流。
发现要求流量尽量少,那么这是个有源汇上下界最小流。
最小流的具体做法:
首先搞出一个可行流。
然后,删掉超级源和超级汇,把求解可行流时汇连向源(注意是普通汇和普通源)的正无穷边删去,然后从源向汇跑一边最大流即可~
原理是,显然当前流可行,需要把多余的流退回去,于是倒着跑一边最大流,尽可能多的退回去~
可行流的答案减去倒着跑最大流的答案即为最终结果。
所以上下界网络流系列全都是套路啊~
#include<bits/stdc++.h>
using namespace std;
const int N=209;
const int M=100009;
const int Inf=1e9+7;
inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}
inline int minn(int a,int b){if(a<b)return a;return b;}
int n,m;
int ex[N];
int s,t,ss,tt;
namespace flows
{
int to[M<<1],nxt[M<<1],w[M<<1],beg[N],tot=1;
int dis[N],q[N],cur[N];
inline void adde(int u,int v,int c)
{
to[++tot]=v;
nxt[tot]=beg[u];
w[tot]=c;
beg[u]=tot;
}
inline void add(int u,int v,int c)
{
adde(u,v,c);adde(v,u,0);
}
inline bool bfs(int s,int t)
{
memset(dis,0,sizeof(dis));
dis[s]=1;q[1]=s;
for(int l=1,r=1,u=q[l];l<=r;u=q[++l])
for(int i=beg[u],v;i;i=nxt[i])
if(!dis[v=to[i]] && w[i]>0)
dis[v]=dis[u]+1,q[++r]=v;
return dis[t];
}
inline int dfs(int u,int t,int mflow)
{
if(u==t || !mflow)return mflow;
int cost=0;
for(int &i=cur[u],v,f;i;i=nxt[i])
if(dis[v=to[i]]==dis[u]+1 && w[i]>0)
{
f=dfs(v,t,minn(mflow-cost,w[i]));
w[i]-=f;w[i^1]+=f;
cost+=f;
if(cost==mflow)break;
}
if(!cost)dis[u]=-1;
return cost;
}
inline int dinic(int s,int t)
{
int ret=0;
while(bfs(s,t))
{
for(int i=0;i<=n+3;i++)
cur[i]=beg[i];
ret+=dfs(s,t,Inf);
}
return ret;
}
inline void del(int x)
{
for(int i=beg[x];i;i=nxt[i])
w[i]=w[i^1]=0;
}
}
using namespace flows;
int main()
{
n=read();
s=0;t=n+1;
ss=n+2;tt=n+3;
for(int i=1;i<=n;i++)
{
m=read();
for(int j=1,v;j<=m;j++)
{
v=read();
ex[i]--;ex[v]++;
add(i,v,Inf);
}
}
for(int i=1;i<=n;i++)
add(s,i,Inf);
for(int i=1;i<=n;i++)
add(i,t,Inf);
for(int i=0;i<=n+1;i++)
if(ex[i]<0)
add(i,tt,-ex[i]);
else if(ex[i]>0)
add(ss,i,ex[i]);
add(t,s,Inf);
dinic(ss,tt);
int ans=w[tot];
w[tot]=w[tot-1]=0;
del(ss);del(tt);
printf("%d\n",ans-dinic(t,s));
return 0;
}