zoukankan      html  css  js  c++  java
  • 狼抓兔子(最大流,反向边不为0)

    狼抓兔子

    https://www.lydsy.com/JudgeOnline/problem.php?id=1001

    Time Limit: 15 Sec  Memory Limit: 162 MB
    Submit: 29629  Solved: 7761
    [Submit][Status][Discuss]

    Description

    现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,
    而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:

     

    左上角点为(1,1),右下角点为(N,M)(上图中N=4,M=5).有以下三种类型的道路 
    1:(x,y)<==>(x+1,y) 
    2:(x,y)<==>(x,y+1) 
    3:(x,y)<==>(x+1,y+1) 
    道路上的权值表示这条路上最多能够通过的兔子数,道路是无向的. 左上角和右下角为兔子的两个窝,
    开始时所有的兔子都聚集在左上角(1,1)的窝里,现在它们要跑到右下解(N,M)的窝中去,狼王开始伏击
    这些兔子.当然为了保险起见,如果一条道路上最多通过的兔子数为K,狼王需要安排同样数量的K只狼,
    才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
    狼的数量要最小。因为狼还要去找喜羊羊麻烦.

    Input

    第一行为N,M.表示网格的大小,N,M均小于等于1000.
    接下来分三部分
    第一部分共N行,每行M-1个数,表示横向道路的权值. 
    第二部分共N-1行,每行M个数,表示纵向道路的权值. 
    第三部分共N-1行,每行M-1个数,表示斜向道路的权值. 
    输入文件保证不超过10M

    Output

    输出一个整数,表示参与伏击的狼的最小数量.

    Sample Input

    3 4
    5 6 4
    4 3 1
    7 5 3
    5 6 7 8
    8 7 6 5
    5 5 5
    6 6 6

    Sample Output

    14

    HINT

     2015.4.16新加数据一组,可能会卡掉从前可以过的程序。

    因为两个点是互通的,所以反向边可以设为w,如果按原来的建边方法,要建两次边,会MLE.....
      1 #include<iostream>
      2 #include<cstring>
      3 #include<string>
      4 #include<cmath>
      5 #include<cstdio>
      6 #include<algorithm>
      7 #include<queue>
      8 #include<vector>
      9 #include<set>
     10 #define maxn 1000005
     11 #define MAXN 1000005
     12 #define mem(a,b) memset(a,b,sizeof(a))
     13 const int N=1000005;
     14 const int M=1000005;
     15 const int INF=0x3f3f3f3f;
     16 using namespace std;
     17 int n;
     18 struct Edge{
     19     int v,next;
     20     int cap,flow;
     21 }edge[MAXN*6];//注意这里要开的够大。。不然WA在这里真的想骂人。。问题是还不报RE。。
     22 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN];
     23 int cnt=0;//实际存储总边数
     24 void isap_init()
     25 {
     26     cnt=0;
     27     memset(pre,-1,sizeof(pre));
     28 }
     29 void isap_add(int u,int v,int w)//加边
     30 {
     31     edge[cnt].v=v;
     32     edge[cnt].cap=w;
     33     edge[cnt].flow=0;
     34     edge[cnt].next=pre[u];
     35     pre[u]=cnt++;
     36 }
     37 void add(int u,int v,int w){
     38     isap_add(u,v,w);
     39     isap_add(v,u,w);
     40 }
     41 bool bfs(int s,int t)//其实这个bfs可以融合到下面的迭代里,但是好像是时间要长
     42 {
     43     memset(dep,-1,sizeof(dep));
     44     memset(gap,0,sizeof(gap));
     45     gap[0]=1;
     46     dep[t]=0;
     47     queue<int>q;
     48     while(!q.empty())
     49     q.pop();
     50     q.push(t);//从汇点开始反向建层次图
     51     while(!q.empty())
     52     {
     53         int u=q.front();
     54         q.pop();
     55         for(int i=pre[u];i!=-1;i=edge[i].next)
     56         {
     57             int v=edge[i].v;
     58             if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是从汇点反向bfs,但应该判断正向弧的余量
     59             {
     60                 dep[v]=dep[u]+1;
     61                 gap[dep[v]]++;
     62                 q.push(v);
     63                 if(v==s)//感觉这两句优化加了一般没错,但是有的题可能会错,所以还是注释出来,到时候视情况而定
     64                 break;
     65             }
     66         }
     67     }
     68     return dep[s]!=-1;
     69 }
     70 int isap(int s,int t)
     71 {
     72     if(!bfs(s,t))
     73     return 0;
     74     memcpy(cur,pre,sizeof(pre));
     75     //for(int i=1;i<=n;i++)
     76     //cout<<"cur "<<cur[i]<<endl;
     77     int u=s;
     78     path[u]=-1;
     79     int ans=0;
     80     while(dep[s]<n)//迭代寻找增广路,n为节点数
     81     {
     82         if(u==t)
     83         {
     84             int f=INF;
     85             for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增广路
     86                 f=min(f,edge[i].cap-edge[i].flow);
     87             for(int i=path[u];i!=-1;i=path[edge[i^1].v])
     88             {
     89                 edge[i].flow+=f;
     90                 edge[i^1].flow-=f;
     91             }
     92             ans+=f;
     93             u=s;
     94             continue;
     95         }
     96         bool flag=false;
     97         int v;
     98         for(int i=cur[u];i!=-1;i=edge[i].next)
     99         {
    100             v=edge[i].v;
    101             if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow)
    102             {
    103                 cur[u]=path[v]=i;//当前弧优化
    104                 flag=true;
    105                 break;
    106             }
    107         }
    108         if(flag)
    109         {
    110             u=v;
    111             continue;
    112         }
    113         int x=n;
    114         if(!(--gap[dep[u]]))return ans;//gap优化
    115         for(int i=pre[u];i!=-1;i=edge[i].next)
    116         {
    117             if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x)
    118             {
    119                 x=dep[edge[i].v];
    120                 cur[u]=i;//常数优化
    121             }
    122         }
    123         dep[u]=x+1;
    124         gap[dep[u]]++;
    125         if(u!=s)//当前点没有增广路则后退一个点
    126         u=edge[path[u]^1].v;
    127      }
    128      return ans;
    129 }
    130  
    131 int main(){
    132     int m,s,t;
    133     cin>>n>>m;
    134     int a,b,c;
    135     isap_init();
    136     s=1,t=n*m;
    137     int v;
    138     for(int i=1;i<=n;i++){
    139         for(int j=1;j<m;j++){
    140             cin>>v;
    141             add(m*(i-1)+j,m*(i-1)+j+1,v);
    142           //  add(m*(i-1)+j+1,m*(i-1)+j,v);
    143           // cout<<m*(i-1)+j<<" "<<m*(i-1)+j+1<<"h"<<endl;
    144         }
    145     }
    146     for(int i=1;i<n;i++){
    147         for(int j=1;j<=m;j++){
    148             cin>>v;
    149             add(m*(i-1)+j,m*i+j,v);
    150           //  add(m*i+j,m*(i-1)+j,v);
    151            // cout<<m*(i-1)+j<<" "<<m*i+j<<"g"<<endl;
    152         }
    153     }
    154     for(int i=1;i<n;i++){
    155         for(int j=1;j<m;j++){
    156             cin>>v;
    157             add(m*(i-1)+j,m*i+j+1,v);
    158          //   add(m*i+j+1,m*(i-1)+j,v);
    159           //  cout<<m*(i-1)+j<<" "<<m*i+j+1<<"g"<<endl;
    160         }
    161     }
    162  //   add(s,1,INF);
    163  //   add(n*m,t,INF);
    164     n=n*m;
    165     cout<<isap(s,t)<<endl;
    166 }
    View Code
  • 相关阅读:
    使用事件模式(Event API)读取Excel2007(.xlsx)文件
    rocketMq消息的发送和消息消费
    Java 七牛云存储与下载
    Spring boot + Jpa + Maven + Mysql 初级整合
    Spring+SpringMvc+Hibernate整合记录
    Mybatis-Generator自动生成代码
    idea spring+springmvc+mybatis环境配置整合详解
    Linux下安装redis
    SpringMvc的基础配置<一>
    JAVA从本机获取IP地址
  • 原文地址:https://www.cnblogs.com/Fighting-sh/p/9829415.html
Copyright © 2011-2022 走看看