LA2957 网络流 蓝书例题

来源:互联网 发布:手机dns优选软件 编辑:程序博客网 时间:2024/05/12 19:34




分析:

首先假设答案为T。构图如下:

把原图的每个点u拆成T+1个,分别为u0,u1,......, 其中u0是初始状态的结点u,ui表示经过i天之后的结点u。对于原图中的相邻结点a和b,在新图中添加一条从ai到bi+1的边,容量为1,再添加一条bi到ai+1的边,容量也为1。对于原图中的每个结点u,添加

ui->ui+1,容量为无穷大,表示飞船可以原地不动。在此图中求最大流,判断流量是否至少为k即可。

逐步增大天数T,每次不要重新求最大流,直接加上一层结点,在上次求出的最大流基础上继续增广,直到流量达到k。

注意,同一时刻ai->bi+1和bi->ai+1不能同时有流量。


代码如下:

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>using namespace std;const int INF = 1e9;const int maxn = 5000+10;const int maxm = 200+10;struct Edge{   int from,to,cap,flow;};bool operator < (const Edge &a,const Edge &b){    return a.from<b.from || (a.from == b.from && a.to<b.to);}vector<Edge>edges;vector<int>G[maxn];bool vis[maxn]; //BFS使用int d[maxn]; //起点到i的距离int cur[maxn]; //当前弧指针int n,m,s,t,k;int u[maxm],v[maxm];queue<int>que;void clearNodes(int a, int b){    for (int i=a; i<=b; i++) G[i].clear();}void init(){   edges.clear();   clearNodes(0,n-1);   for (int i=0; i<m; i++) scanf("%d %d",&u[i],&v[i]);}int sz;void AddEdge(int from, int to, int cap){    edges.push_back((Edge){from,to,cap,0});    edges.push_back((Edge){to,from,0,0});    sz = edges.size();    G[from].push_back(sz-2);    G[to].push_back(sz-1);}bool BFS(int s, int t){   memset(vis,0,sizeof(vis));   while (!que.empty()) que.pop();   que.push(s);   vis[s] = 1;   d[s] = 0;   int x;   while (!que.empty()){       x = que.front();       que.pop();       for (int i=0; i<G[x].size(); i++) {          Edge &e = edges[G[x][i]];          if (!vis[e.to] && e.cap>e.flow) {              vis[e.to] = 1;              d[e.to] = d[x] + 1;              que.push(e.to);          }       }   }   return vis[t];}inline int MIN(int x, int y){return x<y?x:y;}int DFS(int x,int t, int a){   if (x==t || a==0) return a;   int flow = 0, f;   for (int &i=cur[x]; i<G[x].size(); i++){      Edge &e = edges[G[x][i]];      if (d[x]+1==d[e.to] && (f=DFS(e.to,t,MIN(a,e.cap-e.flow)))>0){          flow += f;          a -= f;          e.flow += f;          edges[G[x][i]^1].flow -= f;          if (a==0) break;      }   }   return flow;}int MAXflow(int s, int t, int limit){    int flow = 0;    while (BFS(s,t)){        memset(cur,0,sizeof(cur));        flow += DFS(s,t,limit-flow);        if (flow==limit) break;    }    return flow;}int day,flow;void Print(){   printf("%d\n",day);   int idx = 0;   vector<int> location(k,s);   for (int d=1; d<=day; d++){      idx += n*2;      vector<int>moved(k,0);      vector<int>a,b;      for (int i=0; i<m; i++) {         int f1 = edges[idx].flow; idx+=2;         int f2 = edges[idx].flow; idx+=2;         if (f1==1 && f2==0) {a.push_back(u[i]); b.push_back(v[i]);}         if (f1==0 && f2==1) {a.push_back(v[i]); b.push_back(u[i]);}      }      printf("%d",a.size());      for (int i=0; i<a.size(); i++) {          //查找哪架飞船从a[i]移动到b[i]          for (int j=0; j<k; j++)          if (!moved[j] && location[j]==a[i]){              printf(" %d %d",j+1,b[i]);              moved[j] = 1;              location[j] = b[i];              break;          }      }      printf("\n");   }}int main(){    while (scanf("%d %d %d %d %d",&n,&m,&k,&s,&t)==5){          init();          day = 1, flow = 0;          for (;;){             clearNodes(day*n,day*n+n-1);             for (int i=0; i<n; i++) AddEdge((day-1)*n+i,day*n+i,INF);             for (int i=0; i<m; i++) {                 AddEdge((day-1)*n + u[i]-1, day*n+v[i]-1,1);                 AddEdge((day-1)*n + v[i]-1, day*n+u[i]-1,1);             }             flow += MAXflow(s-1, day*n + t-1, k-flow);             if (k==flow) break;             day++;          }          Print();    }    return 0;}


原创粉丝点击