题解 P2756 【飞行员配对方案问题】

千年知乎_天才

2019-09-26 18:06:13

Solution

题目名称:飞行员配对方案问题 来源:网络流24题 # 链接 ## 博客链接 - [博客园](https://www.cnblogs.com/Alvin-Tree/p/11593308.html) - [CSDN](https://blog.csdn.net/weixin_43890363/article/details/101448496) - [洛谷博客](https://www.luogu.org/blog/131abc155-7341-6424/solution-p2756) - [洛谷题解](https://www.luogu.org/problemnew/solution/P2756) ## 题目链接 - LibreOJ(6000) [题目](https://loj.ac/problem/6000) [提交](https://loj.ac/problem/6000#submit_code) [状态](https://loj.ac/submissions?problem_id=6000) [讨论](https://loj.ac/discussion/problem/6000) - 洛谷(P2756) [题目](https://www.luogu.org/problem/P2756) [提交](https://www.luogu.org/problem/P2756#submit) [状态](https://www.luogu.org/record/list?pid=P2756) [讨论](https://www.luogu.org/discuss/lists?forumname=P2756) # 题目大意 有$n$个英国空军和$m$个外籍空军,一架飞机需要一对互相配合的英国空军和外籍空军配合。给出配合情况,求出最多能发动多少飞机。 # 提示 注意题目来源! # 题解 这是一道最大流裸题。 从原点开始,向每个外籍飞行员连边,容量为$1$。(因为每个外籍飞行员只能被指派一次) 如果外籍飞行员$i$与英国飞行员$j$配合,那么就从$i$向$j$连边,容量为$1$。(每个外籍飞行员与每个英国飞行员最多配合一次) 从每个英国飞行员向汇点连边,容量为$1$。(一对飞行员相互配合只能发动一架飞机) 拿样例说话,如图所示 ![《飞行员配对方案问题》网络图](https://cdn.luogu.com.cn/upload/image_hosting/nlrcjsyc.png) 其中$F$表示外籍飞行员,$E$表示英国飞行员。 然后跑一遍$Dinic$就得到答案了。 ```cpp //C++ #include<bits/locale_facets.h> #include<stdio.h> #include<memory.h> #include<queue> #define downt(i,n) for(int i=n;i;i=back[i]) #define forto(name,i,d,u) for(name i=d;i<=u;i++) #define foruntil(name,i,d,u) for(name i=d;i<u;i++) const int nm=201; inline void output(long long o); inline long long input(); template<int nn,int mm,typename name>struct network{ #define nnn (nn+3) #define mmmm (mm<<2)+2 int s,t,tot,nnnn,last[nnn],level[nnn],to[mmmm],arc[mmmm],back[mmmm]; name c[mmmm]; std::queue<int>q; network(){nnnn=nnn<<2,INIT();} #undef nnn #undef mmmm void INIT(){tot=1,memset(last,0,nnnn);} void add(int f,int t,name cap){to[++tot]=t,c[tot]=cap,back[tot]=last[f],last[f]=tot;} void insert(int f,int t,name cap){ if(cap){ if(cap<0)std::swap(f,t),cap=-cap; add(f,t,cap),add(t,f,0); } }bool climb(){ memset(level,0,nnnn),q.push(s),level[s]=0; for(int p,too;!q.empty();q.pop()){ p=q.front(),level[p]++; downt(i,last[p]) if(c[i]&&!level[too=to[i]])level[too]=level[p],q.push(too); }return level[t]; }name augment(int p,name m){ if(p==t)return m; name sum=0,flow; int d=level[p]+1; for(;arc[p];arc[p]=back[arc[p]]) if(level[to[arc[p]]]==d&&c[arc[p]]){ sum+=(flow=augment(to[arc[p]],std::min(c[arc[p]],(name)(m-sum)))),c[arc[p]]-=flow,c[arc[p]^1]+=flow; if(sum==m)return m; }return sum; }name Dinic(name inf){ name maximum=0; while(climb()){ foruntil(int,i,s,t)arc[i]=last[i]; maximum+=augment(s,inf); }return maximum; } void new1(short m){ short n=input(),a,b; s=0,t=n+m+1; forto(short,i,1,m)insert(0,i,1); forto(short,i,m+1,m+n)insert(i,t,1); while(true){ if((a=input())==-1)break; insert(a,input(),1); }output(Dinic(100)),putchar('\n'); forto(short,i,1,m) for(short j=last[i];back[j];j=back[j]) if(!c[j])output(i),putchar(' '),output(to[j]),putchar('\n'); } };network<200,40000,short>pilot; int main(){ pilot.new1(input()); return 0; }inline void output(long long o){ if(o<0)putchar('-'),o=-o; if(o>=10)output(o/10); putchar(o%10^'0'); }inline long long input(){ bool minus=false; char now=getchar(); long long i=0; for(;!isdigit(now);now=getchar()) if(now=='-')minus=!minus; for(;isdigit(now);now=getchar())i=(i<<3)+(i<<1)+(now^'0'); return minus?-i:i; } ``` # 题集 - [网络流24题](https://blog.csdn.net/weixin_43890363/article/details/101509320) 希望这些外籍飞行员里能有中国飞行员。 还是中国飞行员强。