LA2957 网络流 蓝书例题




分析:

首先假设答案为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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值