zoukankan      html  css  js  c++  java
  • poj 2391(二分+最大流)

    题目链接:http://poj.org/problem?id=2391

    思路:求最短时间,可以想到二分,然后判断可行性。首先在原图上求 floyd,得到每两个棚之间的最短距离。然后拆点:将每个棚拆为 i 和 i’(流进和流出),添边(i,i’,INF)。增加源点 s 和汇点 t,从 s 连边到 i,容量为该棚现在的猫的数量,i’连边到 t,容量为该棚的容量。若棚 i 和棚 j 之间的距离不大于 limit,则连边(i,j’,INF), (j,i’,INF)。求最大流,若从 s 发出的边均满流,则在 low 和 mid 中搜索;否则在 mid 和 high 中搜索。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<queue>
      6 using namespace std;
      7 #define MAXN 444
      8 #define MAXM 44444444
      9 #define inf 1<<30
     10 #define INF 1LL<<60
     11 
     12 struct Edge{
     13     int v,cap,next;
     14 }edge[MAXM];
     15 
     16 int n,m,NE,vs,vt,NV;
     17 int head[MAXN];
     18 
     19 void Insert(int u,int v,int cap)
     20 {
     21     edge[NE].v=v;
     22     edge[NE].cap=cap;
     23     edge[NE].next=head[u];
     24     head[u]=NE++;
     25 
     26     edge[NE].v=u;
     27     edge[NE].cap=0;
     28     edge[NE].next=head[v];
     29     head[v]=NE++;
     30 }
     31 
     32 int level[MAXN],gap[MAXN];
     33 void bfs(int vt)
     34 {
     35     memset(level,-1,sizeof(level));
     36     memset(gap,0,sizeof(gap));
     37     level[vt]=0;
     38     gap[level[vt]]++;
     39     queue<int>que;
     40     que.push(vt);
     41     while(!que.empty()){
     42         int u=que.front();
     43         que.pop();
     44         for(int i=head[u];i!=-1;i=edge[i].next){
     45             int v=edge[i].v;
     46             if(level[v]<0){
     47                 level[v]=level[u]+1;
     48                 gap[level[v]]++;
     49                 que.push(v);
     50             }
     51         }
     52     }
     53 }
     54 
     55 int pre[MAXN],cur[MAXN];
     56 int SAP(int vs,int vt)
     57 {
     58     bfs(vt);
     59     memset(pre,-1,sizeof(pre));
     60     memcpy(cur,head,sizeof(head));
     61     int maxflow=0,aug=inf;
     62     int u=pre[vs]=vs;
     63     gap[0]=NV;
     64     while(level[vs]<NV){
     65         bool flag=false;
     66         for(int &i=cur[u];i!=-1;i=edge[i].next){
     67             int v=edge[i].v;
     68             if(edge[i].cap>0&&level[u]==level[v]+1){
     69                 flag=true;
     70                 pre[v]=u;
     71                 u=v;
     72                 aug=min(aug,edge[i].cap);
     73                 if(v==vt){
     74                     maxflow+=aug;
     75                     for(u=pre[v];v!=vs;v=u,u=pre[u]){
     76                         edge[cur[u]].cap-=aug;
     77                         edge[cur[u]^1].cap+=aug;
     78                     }
     79                     aug=inf;
     80                 }
     81                 break;
     82             }
     83         }
     84         if(flag)continue;
     85         int minlevel=NV;
     86         for(int i=head[u];i!=-1;i=edge[i].next){
     87             int v=edge[i].v;
     88             if(edge[i].cap>0&&level[v]<minlevel){
     89                 minlevel=level[v];
     90                 cur[u]=i;
     91             }
     92         }
     93         if(--gap[level[u]]==0)break;
     94         level[u]=minlevel+1;
     95         gap[level[u]]++;
     96         u=pre[u];
     97     }
     98     return maxflow;
     99 }
    100 
    101 int now_num[MAXN],num[MAXN];
    102 long long dist[MAXN][MAXN];
    103 void Floyd()
    104 {
    105     for(int k=1;k<=n;k++)
    106         for(int i=1;i<=n;i++)
    107             for(int j=1;j<=n;j++)
    108                 if(dist[i][k]<INF&&dist[k][j]<INF&&dist[i][k]+dist[k][j]<dist[i][j])
    109                     dist[i][j]=dist[i][k]+dist[k][j];
    110 }
    111 
    112 void Build(long long limit)
    113 {
    114     NE=0;
    115     memset(head,-1,sizeof(head));
    116     vs=0,vt=2*n+1,NV=2*n+2;
    117     for(int i=1;i<=n;i++)Insert(vs,i,now_num[i]);
    118     for(int i=1;i<=n;i++)Insert(i+n,vt,num[i]);
    119     for(int i=1;i<=n;i++)Insert(i,i+n,inf);
    120     for(int i=1;i<=n;i++){
    121         for(int j=i+1;j<=n;j++){
    122             if(dist[i][j]<=limit){
    123                 Insert(i,j+n,inf);
    124                 Insert(j,i+n,inf);
    125             }
    126         }
    127     }
    128 }
    129 
    130 int main()
    131 {
    132     int u,v,sum;
    133     long long w,low,high,mid,ans,limit;
    134     while(~scanf("%d%d",&n,&m)){
    135         limit=sum=0;
    136         for(int i=1;i<=n;i++){
    137             scanf("%d%d",&now_num[i],&num[i]);
    138             sum+=now_num[i];
    139         }
    140         for(int i=1;i<=n;i++)
    141             for(int j=1;j<=n;j++)
    142                 dist[i][j]=(i==j)?0:INF;
    143         while(m--){
    144             scanf("%d%d%lld",&u,&v,&w);
    145             limit+=w;
    146             if(dist[u][v]>w){
    147                 dist[u][v]=dist[v][u]=w;
    148             }
    149         }
    150         Floyd();
    151         low=0,high=limit+1,mid,ans=-1;
    152         while(low<=high){
    153             mid=(low+high)>>1;
    154             Build(mid);
    155             if(SAP(vs,vt)==sum){
    156                 ans=mid;
    157                 high=mid-1;
    158             }else
    159                 low=mid+1;
    160         }
    161         printf("%lld
    ",ans);
    162     }
    163     return 0;
    164 }
    View Code
  • 相关阅读:
    不注意的小问题
    Hibernate、Spring和Struts工作原理及使用理由
    正则表达式贪婪与非贪婪模式
    Springmvc构造RESTful详细讲解
    正则表达式贪婪与非贪婪模式1
    BOJ二叉排序树的后序遍历
    qsort()应用大全
    辗转相除法求最大公约数(C语言)
    九度题目1014:排名 (结构体多级排序)
    BOJ第三题:二叉树前序遍历
  • 原文地址:https://www.cnblogs.com/wally/p/3278676.html
Copyright © 2011-2022 走看看