http://www.lydsy.com/JudgeOnline/problem.php?id=1001
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MB
Submit: 24017 Solved: 6068
[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新加数据一组,可能会卡掉从前可以过的程序。
【解析】:
解法1:网络流dinic算法,但需要很多地方优化才能不超时,比如
1.dfs过程中,如果某一步,从某点递归返回的最大流没有正数值,则增广路已经找完,直接把标号d[s]=-1,就能终止递归。
2.bfs标号过程中,只要遇到汇点,就立即return,不做后面的无用功
解法2:把每个环路围成的区域看做一个点,建好图,从右上角往左下角跑一边最短路,就能把图切开。
【代码1】:(dinic)
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <string.h>
- #include <iostream>
- #include <algorithm>
- #include <queue>
- #define mset(a,i) memset(a,i,sizeof(a))
- #define S1(n) scanf("%d",&n)
- #define S2(n,m) scanf("%d%d",&n,&m)
- #define P(n) printf("%d\n",n)
- using namespace std;
- typedef long long ll;
- const int INF=0x3f3f3f3f;
- const int MAX=1e6+5;
- int n,m;
- struct node{
- int u,v,w,next;
- }edge[6*MAX];
- int head[MAX];
- int d[MAX];
- void add(int u,int v,int w)
- {
- static int cnt=0;
- edge[cnt].v=v;
- edge[cnt].w=w;
- edge[cnt].next=head[u];
- head[u]=cnt++;
- }
- int bfs(int s,int t)
- {
- mset(d,0);
- d[s]=1;
- queue <int> q;
- q.push(s);
- while(!q.empty())
- {
- int u=q.front();
- q.pop();
- if(u==t) return 1;
- for(int i=head[u];i!=-1;i=edge[i].next)
- {
- int v=edge[i].v;
- int w=edge[i].w;
- if(w&&d[v]==0)
- {
- d[v]=d[u]+1;
- if(v==t)
- return 1;
- q.push(v);
- }
- }
- }
- return 0;
- }
- int dfs(int s,int t,int maxflow=INF)
- {
- if(s==t)
- return maxflow;
- int i,j,ret=0;
- for(i=head[s];i!=-1;i=edge[i].next)
- {
- int v=edge[i].v;
- int w=edge[i].w;
- if(w&&d[v]==d[s]+1)
- {
- int temp=dfs(v,t,min(maxflow-ret,w));
- edge[i].w-=temp;
- edge[i^1].w+=temp;
- ret+=temp;
- if(ret==maxflow)
- return ret;
- }
- }
- if(!ret)
- d[s]=-1;
- return ret;
- }
-
- int dinic(int s,int t)
- {
- int ans=0;
- while(bfs(s,t))
- {
- ans+=dfs(s,t);
- }
- return ans;
- }
-
- int main()
- {
- S2(n,m);
- mset(head,-1);
- int s,t,cap;
- for(int i=0;i<n;i++)
- for(int j=1;j<m;j++)
- {
- s=i*m+j;t=s+1;
- S1(cap);
- add(s,t,cap);
- add(t,s,cap);
- }
- for(int i=0;i<n-1;i++)
- for(int j=1;j<=m;j++)
- {
- s=i*m+j;t=s+m;
- S1(cap);
- add(s,t,cap);
- add(t,s,cap);
- }
- for(int i=0;i<n-1;i++)
- for(int j=1;j<m;j++)
- {
- s=i*m+j;t=s+m+1;
- S1(cap);
- add(s,t,cap);
- add(t,s,cap);
- }
- int ans=dinic(1,n*m);
- P(ans);
- return 0;
- }
【代码2】(spfa)
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <iostream>
- #include <algorithm>
- #include <string>
- #include <queue>
- #include <stack>
- #include <vector>
- #include <set>
- #include <list>
- #include <map>
- #define mset(a,i) memset(a,i,sizeof(a))
- #define S1(n) scanf("%d",&n)
- #define S2(n,m) scanf("%d%d",&n,&m)
- #define P(n) printf("%d\n",n);
- #define FIN freopen("input.txt","r",stdin)
- #define FOUT freopen("output.txt","w",stdout)
- #define gcd(a,b) __gcd(a,b)
- using namespace std;
- typedef long long ll;
- const double eps=1e-6;
- const int INF=0x3f3f3f3f;
- const int mod=1e9+7;
- const int MAX=1e6+5;
- const double PI=acos(-1);
- int dir[5][2]={0,1,0,-1,1,0,-1,0};
- ll qpow(ll n,ll m){n%=mod;ll ans=1;while(m){if(m%2)
- ans=(ans*n)%mod;m/=2;n=(n*n)%mod;}return ans;}
- ll inv(ll b){return b==1?1:(mod-mod/b)*inv(mod%b)%mod;}
- ll inv2(ll b){return qpow(b,mod-2);}
- struct node{
- int s,t,len,next;
- }edge[6000010];
- int head[2000100];
- int n,m,len;
- int dis[2000100];
- int tail=1;
- void add(int s,int t,int l)
- {
- edge[tail].s=s;
- edge[tail].t=t;
- edge[tail].len=l;
- edge[tail].next=head[s];
- head[s]=tail++;
- }
- int spfa(int s,int t)
- {
- mset(dis,INF);
- dis[s]=0;
- queue<int> q;
- q.push(s);
- while(!q.empty())
- {
- int u=q.front();
- q.pop();
- for(int i=head[u];i!=-1;i=edge[i].next)
- {
- int v=edge[i].t;
- if(dis[v]>dis[u]+edge[i].len)
- {
- dis[v]=dis[u]+edge[i].len;
- q.push(v);
- }
- }
- }
- return dis[t];
- }
- int main()
- {
- S2(n,m);
- if(n==1&&m==1){
- puts("0");
- return 0;
- }
- mset(head,-1);
- int end=2*(m-1)*(n-1)+1;
- for(int i=1;i<m;i++){
- S1(len);
- add(0,i,len);
- add(i,0,len);
-
- }
- for(int i=1;i<n-1;i++)
- {
- for(int j=1;j<m;j++){
- S1(len);
- int d=2*(m-1)*i+j;
- int u=d-(m-1);
- add(u,d,len);
- add(d,u,len);
-
- }
- }
- if(n>1)
- for(int i=1;i<m;i++){
- S1(len);
- int u=end-(m-i);
- add(u,end,len);
- add(end,u,len);
-
- }
-
- for(int i=0;i<n-1;i++)
- {
- S1(len);
- int r=2*(m-1)*(i+1)-(m-2);
- if(m==1)r=0;
- add(r,end,len);
- add(end,r,len);
-
- for(int j=1;j<m-1;j++){
- S1(len);
- int l=2*(m-1)*i+j;
- int r=l+m;
- add(l,r,len);
- add(r,l,len);
-
- }
- if(m<=1)continue;
- S1(len);
- int l=2*(m-1)*i+m-1;
- add(0,l,len);
- add(l,0,len);
-
- }
-
- for(int i=0;i<n-1;i++)
- {
- for(int j=1;j<m;j++){
- S1(len);
- int u=2*(m-1)*i+j;
- int d=u+m-1;
- add(u,d,len);
- add(d,u,len);
-
- }
- }
- int ans=spfa(0,end);
- P(ans);
- return 0;
- }