bzoj1001 狼抓兔子

题意

现在小朋友们最喜欢的”喜羊羊与灰太狼”,话说灰太狼抓羊不到,但抓兔子还是比较在行的,
而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
这里写图片描述
左上角点为(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只狼,
才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的
狼的数量要最小。因为狼还要去找喜羊羊麻烦.
输入
第一行为N,M.表示网格的大小,N,M均小于等于1000.
接下来分三部分
第一部分共N行,每行M-1个数,表示横向道路的权值.
第二部分共N-1行,每行M个数,表示纵向道路的权值.
第三部分共N-1行,每行M-1个数,表示斜向道路的权值.
输入文件保证不超过10M
输出
输出一个整数,表示参与伏击的狼的最小数量.
样例输入
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
样例输出
14

解题思路

一样看上去像是道网络流题,但貌似正解不是网络流,本蒟蒻还是用网络流来写了,这道题建图很简单,就把每个点按照从上到下从左往右的顺序依次编号就好,比如样例的点的编号是
0 1 2 3
4 5 6 7
8 9 10 11
但发现有三个坑:

  1. 直接用dinic会TLE,需要炸点和多路增广优化。
  2. 是一个无向图,刚开始把反向边的容量设置为0,结果怎么都过不了样例,后来才发现是无向图,反向边的容量要与正向边一致,或者说没有反向边这种说法。
  3. 题目中的n和m最大是1000,所以最多存在1e6个点,但边却有2(n(m-1)+(n-1)m+(n-1)(m-1))条,极限数量大概在6*1e6以下,一开始数组开小还RE了几发。

在解决了这几个坑后,终于ac了,但发现了一个问题,如果数组开到1e7,在洛谷可以过,在vj却会MLE。
版权声明:本文为原创文章,转载请标明出处。
https://blog.csdn.net/u014390156

AC代码如下:

#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#define rep(i,x,n) for(int i=x;i<n;i++)
#define per(i,x,n) for(int i=n-1;i>=x;i--)
using namespace std;
//head
typedef long long ll;
int const maxn=6000006;
struct Edge{int next,to,cap;}edge[maxn];
int head[maxn],flag[maxn],n,m,v,cur,t;
int cnt=0;
void addedge(int i,int j)
{
    int num=i*m+j,num2;
    if(cur==1)num2=num+1;
    else if(cur==2)num2=num+m;
    else if(cur==3)num2=num+m+1;
    edge[cnt].to=num2;edge[cnt].cap=v;edge[cnt].next=head[num];head[num]=cnt;cnt++;
    edge[cnt].to=num;edge[cnt].cap=v;edge[cnt].next=head[num2];head[num2]=cnt;cnt++;
}
int bfs()
{
    memset(flag,0,sizeof(flag));
     queue<int>q;
     q.push(0);
     flag[0]=1;
     while(!q.empty())
     {
         int x=q.front();q.pop();
         for(int i=head[x];i!=-1;i=edge[i].next)
         {
             if(!flag[edge[i].to]&&edge[i].cap)
                flag[edge[i].to]=flag[x]+1,q.push(edge[i].to);
         }
     }
     return flag[t];
}
int dfs(int fl,int num)
{
    if(num==t)return fl;
    int f=0;
    for(int i=head[num];i!=-1&&fl;i=edge[i].next)
    {
        if(flag[edge[i].to]==flag[num]+1&&edge[i].cap)
        {
            int x=dfs(min(fl,edge[i].cap),edge[i].to);
            fl-=x;f+=x;edge[i].cap-=x;edge[i^1].cap+=x;
        }
    }
    if(!f)flag[num]=-2;
   return f;
}
ll maxflow()
{
    ll ret=0;
    while(bfs()){ret+=dfs(1<<30,0);}
    return ret;
}
int main()
{
     ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
     cin>>n>>m;t=n*m-1;
     memset(head,-1,sizeof(head));
     cur=1;rep(i,0,n)rep(j,0,m-1){cin>>v;addedge(i,j);}
     cur=2;rep(i,0,n-1)rep(j,0,m){cin>>v;addedge(i,j);}
     cur=3;rep(i,0,n-1)rep(j,0,m-1){cin>>v;addedge(i,j);}
     cout<<maxflow()<<endl;
     return 0;
}

猜你喜欢

转载自blog.csdn.net/u014390156/article/details/82598471
今日推荐