题目描述
滑雪场坐落在FJ省西北部的若干座山上。
从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向。
你的团队负责每周定时清理雪道。你们拥有一架直升飞机,每次飞行可以从总部带一个人降落到滑雪场的某个地点,然后再飞回总部。从降落的地点出发,这个人可以顺着斜坡向下滑行,并清理他所经过的雪道。
由于每次飞行的耗费是固定的,为了最小化耗费,你想知道如何用最少的飞行次数才能完成清理雪道的任务。
输入格式
输入文件的第一行包含一个整数n (2 <= n <= 100) – 代表滑雪场的地点的数量。
接下来的n行,描述1~n号地点出发的斜坡,第i行的第一个数为mi (0 <= mi < n) ,后面共有mi个整数,由空格隔开,每个整数aij互不相同,代表从地点i下降到地点aij的斜坡。每个地点至少有一个斜坡与之相连。
输出格式
输出文件的第一行是一个整数k – 直升飞机的最少飞行次数。
输入输出样例
输入 #1复制
8 1 3 1 7 2 4 5 1 8 1 8 0 2 6 5 0
输出 #1复制
View Code
4
建立超级源点和超级汇点 超级源点像每个点连inf 每个点像超级汇点连inf 两个点之间如果能到达那么连边(如果可以保证这条边的流量至少为1的话 跑出最小流 显然就是这题的答案)
套上有源汇最小流模板即可
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define pb push_back #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) // #define inf 0x3f3f3f3f const int N=4e3+44; const int M=4e4+54; int d[N]; struct edge { int to, next, w; } e[M << 1]; int head[N],cur[N],cnt = 1; void add(int x, int y, int z) { e[++cnt] = (edge){y, head[x], z}; head[x] = cnt; e[++cnt] = (edge){x, head[y], 0}; head[y] = cnt; } void ins(int x,int y,int a,int b) { add(x,y,b-a); d[x]-=a; d[y]+=a; } int level[N]; bool bfs(int s, int t) { memset(level, 0, sizeof level); queue<int> q; level[s] = 1; q.push(s); while (!q.empty()) { int pos = q.front();q.pop(); for (int i = head[pos]; i; i = e[i].next) { int nx = e[i].to; if (!e[i].w || level[nx]) continue; level[nx] = level[pos] + 1; q.push(nx); } } return level[t]; } int dfs(int s, int t, int flow) { if(s==t||flow==0)return flow; int f,ret = 0; for (int &i = cur[s],v; i; i = e[i].next) { v = e[i].to; if (level[v] == level[s] + 1 && (f=dfs(v,t,min(flow,e[i].w)))>0) { e[i].w -= f; e[i ^ 1].w += f; flow -= f; ret += f; if(!flow)break; } } return ret; } int dinic(int s, int t) { int ret = 0; while (bfs(s, t)) memcpy(cur,head,sizeof cur),ret += dfs(s, t, inf); return ret; } int n,m,s,t,a,b,c,sum,S,T; int main() { scanf("%d",&n); s=n+1,t=s+1;S=t+1,T=S+1; rep(i,1,n) { ins(s,i,0,inf);ins(i,t,0,inf); int k;scanf("%d",&k); while(k--) { int x;scanf("%d",&x); ins(i,x,1,inf); } } rep(i,1,n) if(d[i]>0)add(S,i,d[i]); else if(d[i]<0)add(i,T,-d[i]); dinic(S,T); add(t,s,inf); dinic(S,T); cout<<e[cnt].w; return 0; }