zoukankan      html  css  js  c++  java
  • [网络流24题] 13. 星际转移问题 解题报告

    13.星际转移问题

    题意

    (n) 个太空站, (m) 艘太空船,

    太空船 (i) 一次能容下 (h_i) 个人,

    每艘太空船会按照自己的航线循环行驶, 每行驶一个站点需要一个单位时间,

    求从节点 (0) 到节点 (n+1) 所需的最小时间.


    思路

    一道一开始完全没有思路的题, 后来发现姆爷又发了新专, 果断地剁手后听了一会, 这道题就想出来了......


    总思路是把每个太空站都按时间分为若干个节点,

    也就是说, 每加一个单位时间, 我们就把这总共 (n+2) 个点全部建一遍 (包括 (0) 节点和 (n+1) 节点).

    对于每艘太空船, 我们都按照它的航线向右建边, 也就是向它下一个单位时刻会到达的节点连边,

    除此之外, 每个时刻的每个太空站还要向下一时刻的自己连边, 容量为 (inf), 表示在等太空船.


    题解的做法是先用并查集判断是否能到达终点, 然后按时间依次加点加边, 在残量网络上跑最大流就行了.

    我比较蠢.....先随便选了一个很大的数作为总时间, 然后直接把整张图建出来跑了一个最小费用最大流...


    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int _=20+7;
    const int __=700+7;
    const int ___=3e3+7;
    const int inf=0x3f3f3f3f;
    int n,m,num,S,T,des,st[_],dis[__],max_flow,ans,limit=30;
    int lst[__],nxt[___],to[___],c[___],w[___],tot=1;
    bool vis[__];
    queue<int> q;
    void add(int x,int y,int cap,int wgt){
      //printf("(%d,%d,%d,%d)
    ",x,y,cap,wgt);
      nxt[++tot]=lst[x]; to[tot]=y; c[tot]=cap; w[tot]=wgt; lst[x]=tot;
      nxt[++tot]=lst[y]; to[tot]=x; c[tot]=0; w[tot]=-wgt; lst[y]=tot;
    }
    void init(){
      cin>>n>>m>>num; 
      S=(n+2)*(limit+1); T=S+1; des=T+1;
      int h,cy;
      for(int i=1;i<=m;i++){
        scanf("%d%d",&h,&cy);
        for(int j=1;j<=cy;j++){
          scanf("%d",&st[j]);
          if(st[j]==-1) st[j]=n+1;
        }
        int time=0,j=1,t=0;
        while(time<limit){
          int x=st[j],y=st[j==cy ?1 :j+1];
          add(x+t,y+t+n+2,h,1);
          t+=n+2; time++;
          j= j==cy ?1 :j+1;
        }
      }
      for(int t=0;t<limit;t++){
        int tt=t*(n+2);
        for(int i=0;i<=n+1;i++)
          add(i+tt,i+tt+n+2,inf,1);
      }
      add(S,0,num,0);
      add(des,T,num,0);
      for(int i=0;i<=limit;i++)
        add(n+1+i*(n+2),des,inf,0);
    }
    bool SPFA(){
      for(int i=0;i<=des;i++){ dis[i]=inf; vis[i]=0; }
      while(!q.empty()) q.pop();
      dis[S]=0; q.push(S);
      while(!q.empty()){
        int u=q.front(); q.pop();
        vis[u]=0;
        for(int i=lst[u];i;i=nxt[i]){
          int v=to[i];
          if(!c[i]||dis[v]<=dis[u]+w[i]) continue;
          dis[v]=dis[u]+w[i];
          if(!vis[v]){
    	q.push(v);
    	vis[v]=1;
          }
        }
      }
      memset(vis,0,sizeof(vis));
      return dis[T]!=inf;
    }
    int dfs(int u,int flow){
      if(u==T) return flow;
      int rest=flow; vis[u]=1;
      for(int i=lst[u];i;i=nxt[i]){
        int v=to[i];
        if(vis[v]||dis[v]!=dis[u]+w[i]||!c[i]) continue;
        int cst=dfs(v,min(rest,c[i]));
        if(cst==0) dis[v]=inf;
        else{
          c[i]-=cst; c[i^1]+=cst;
          rest-=cst; 
        }
      }
      vis[u]=0;
      return flow-rest;
    }
    void Dinic(){
      int flow;
      while(SPFA())
        do{
          flow=dfs(S,inf);
          max_flow+=flow;
        }while(flow);
      //printf("max_flow: %d
    ",max_flow);
    }
    void print(){
      for(int i=lst[des];i;i=nxt[i])
        if(to[i]!=T&&c[i]&&to[i]>ans) ans=to[i];
      ans=(ans-(n+1))/(n+2);
      printf("%d
    ",ans);
    }
    int main(){
    #ifndef ONLINE_JUDGE
      freopen("x.in","r",stdin);
    #endif
      init();
      Dinic();
      if(max_flow<num) puts("0");
      else print();
      return 0;
    }
    
  • 相关阅读:
    spring mvc常用配置
    spring data redis使用1——连接的创建
    spring session使用小记
    log4j2使用入门(一)
    com.google.common.eventbus.EventBus介绍
    使用java远程调试技术监控代码运行
    阿里云数加平台——数据同步任务调度及管理
    阿里云数加平台——BI报表使用概述和总结
    解决因block的损坏而导致hdfs启动后进入安全模式
    iOS 6 自动布局入门
  • 原文地址:https://www.cnblogs.com/BruceW/p/12207372.html
Copyright © 2011-2022 走看看