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
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 210000000
using 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;
}