题意
滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
n<=100
题解
题目抽象出来就是用最少的路径数覆盖一个DAG,即每条边至少经过一次。
直接搞成有源汇有上下界的最小流即可,建图很简单:
S–>i 容量无限大,i–>T 容量无限大
i–>j 容量
[1,+∞]
然后就好了。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1005,maxe=200005;
struct Edge{
int from,to,flow,cap;
Edge(int t1=0,int t2=0,int t3=0,int t4=0){ from=t1; to=t2; flow=t3; cap=t4; }
} Es[maxe];
int fir[maxn],nxt[maxe],tot=1;
void add(int x,int y,int z){
Es[++tot]=Edge(x,y,0,z); nxt[tot]=fir[x]; fir[x]=tot;
Es[++tot]=Edge(y,x,0,0); nxt[tot]=fir[y]; fir[y]=tot;
}
queue <int> que;
int S,T,SS,TT,N,d[maxn],tmp[maxn];
int n,ans0;
bool Bfs(int S,int T){
memset(d,63,sizeof(d)); int INF=d[0];
while(!que.empty()) que.pop();
que.push(S); d[S]=0;
while(!que.empty()){
int x=que.front(); que.pop();
for(int j=fir[x];j;j=nxt[j]) if(d[Es[j].to]==INF&&Es[j].cap>Es[j].flow){
d[Es[j].to]=d[x]+1; que.push(Es[j].to);
}
}
return d[T]!=INF;
}
int pos[maxn];
int find_Dfs(int x,int flow,int T){
if(x==T||flow==0) return flow;
int res=0,t;
for(int &j=pos[x];j;j=nxt[j]){
if(d[x]+1==d[Es[j].to]&&(t=find_Dfs(Es[j].to,min(flow,Es[j].cap-Es[j].flow),T))>0){
Es[j].flow+=t; Es[j^1].flow-=t;
res+=t; flow-=t; if(flow==0) break;
}
}
return res;
}
int Dinic(int S,int T){
int MaxFlow=0;
while(Bfs(S,T)){
for(int i=1;i<=N;i++) pos[i]=fir[i];
MaxFlow+=find_Dfs(S,1e+9,T);
}
return MaxFlow;
}
void Del(int x){
for(int j=fir[x];j;j=nxt[j]) Es[j].flow=Es[j].cap=Es[j^1].flow=Es[j^1].cap=0;
}
int main(){
freopen("bzoj2502.in","r",stdin);
freopen("bzoj2502.out","w",stdout);
scanf("%d",&n);
N=n; S=++N; T=++N; SS=++N; TT=++N;
for(int i=1;i<=n;i++){
int t,x; scanf("%d",&t);
while(t--){
scanf("%d",&x);
add(i,x,1e+9); tmp[i]--; tmp[x]++;
}
}
for(int i=1;i<=n;i++) add(S,i,1e+9), add(i,T,1e+9);
for(int i=1;i<=n;i++){
if(tmp[i]>0) add(SS,i,tmp[i]);
else add(i,TT,-tmp[i]);
}
add(T,S,1e+9);
Dinic(SS,TT); ans0=Es[tot-1].flow+0;
Es[tot].cap=Es[tot].flow=Es[tot-1].cap=Es[tot-1].flow=0; Del(SS); Del(TT);
printf("%d\n",ans0-Dinic(T,S));
return 0;
}