Evanyou Blog 彩带

网络流二十四题之飞行员配对问题

  先上题目传送门

  很明显的一个二分图,用匈牙利算法也可以轻松水过,但既然是网络流二十四题,当然是用网络流的算法才对嘛。

  数据很小,而且基本没什么思维难度,在外籍飞行员与英国飞行员之间连边形成一个图,然后建一个超级源点和一个超级汇点,再跑dinic或ISAP就可以了。

  至于输出配对的问题,只需要扫一边每一条正边(千万不能扫负边),判断改变的反向边容量是否大于0,如果大于0,就输出该边连的两个点。  

  很水吧?

  上代码(这里我用的dinic算法):

  

#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define inf 1e9
using namespace std;
const int N=505;
const int M=500050;
int n,m,ans,start,endd;
int head[N],size=1,cur[N];
int depth[N];
struct Node{
  int from,to,val,next;
}edge[M<<1];
inline int read()
{
  char ch=getchar();int num=0;bool flag=false;
  while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
  while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
  return flag?-num:num;
}
inline void add(int x,int y,int z)
{
  edge[++size].from=x;
  edge[size].to=y;
  edge[size].val=z;
  edge[size].next=head[x];
  head[x]=size;
}
inline void add_edge(int x,int y)
{add(x,y,1);add(y,x,0);}
void ready()
{
  memset(head,-1,sizeof(head));
  m=read();n=read();
  start=0;endd=n+1;
  for(int i=1;i<=m;i++)
    add_edge(start,i);
  int x=read();int y=read();
  while(x!=-1&&y!=-1){
    add_edge(x,y);
    x=read();y=read();
  }
  for(int i=m+1;i<=n;i++)
    add_edge(i,endd);
}
inline bool bfs()
{
  queue<int>team;
  memset(depth,0,sizeof(depth));
  depth[start]=1;team.push(start);
  while(!team.empty()){
    int x=team.front();team.pop();
    for(int i=head[x];i!=-1;i=edge[i].next){
      int y=edge[i].to;
      if(depth[y]==0&&edge[i].val>0){
    depth[y]=depth[x]+1;
    team.push(y);
      }
    }
  }
  return depth[endd]>0?true:false;
}
inline int dfs(int u,int flow)
{
  if(u==endd||flow==0)return flow;
  for(int& i=cur[u];i!=-1;i=edge[i].next){
    int v=edge[i].to;
    if(edge[i].val>0&&depth[v]==depth[u]+1){
      int ka=dfs(v,min(edge[i].val,flow));
      if(ka>0){
    edge[i].val-=ka;
    edge[i^1].val+=ka;
    return ka;
      }
    }
  }
  return 0;
}
void work()
{
  while(bfs()){
    for(int i=start;i<=endd;i++)
      cur[i]=head[i];
    while(int d=dfs(start,inf))
      ans+=d;
  }
}
void solve()
{
  if(ans==0)
    {cout<<"No Solution!";
      return ;}
  printf("%d\n",ans);
  for(int i=0;i<=size;i+=2){
    int x=edge[i].from;
    int y=edge[i].to;
    if(x==start||y==start)
      continue;
    if(x==endd||y==endd)
      continue;
    if(edge[i^1].val>0){
      printf("%d %d\n",x,y);
    }
  }
}
int main()
{
  ready();
  work();
  solve();
  return 0;
}

 

posted @ 2017-12-22 10:38  HolseLee  阅读(219)  评论(0编辑  收藏  举报