码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ1001: [BeiJing2006]狼抓兔子

时间:2018-05-14 13:19:54      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:discus   bsp   ems   ima   信息   get   clu   ret   参与   

法一:以左上角为源,右下角为汇,按原图建图求最小割。

法二:平面图最小割转对偶图最短路,可见集训队论文《两极相通——浅谈最大最小定理在信息学竞赛中的应用》。

//法一
#include<bits/stdc++.h> #define rep(i,l,r) for (int i=l;i<=r;i++) using namespace std; const int maxn=1000005,inf=0x3f3f3f3f; int n,m,tot=1,S,T; long long ans; int read(){ int ans=0,f=1,c=getchar(); while(c<0||c>9) {if(c==-) f=-1; c=getchar();} while(c>=0&&c<=9) {ans=ans*10+(c-0); c=getchar();} return ans*f; } int head[maxn],d[maxn],q[maxn],cur[maxn]; struct node{int flow,obj,pre;}e[6*maxn]; void add(int a,int b,int w){ tot++; e[tot].obj=b; e[tot].flow=w; e[tot].pre=head[a]; head[a]=tot; tot++; e[tot].obj=a; e[tot].flow=w; e[tot].pre=head[b]; head[b]=tot; } int bfs(){ rep(i,1,n*m) d[i]=-1; queue<int> q; q.push(S); d[S]=0; while (!q.empty()){ int u=q.front(); q.pop(); for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (d[v]==-1&&e[j].flow) d[v]=d[u]+1,q.push(v); } } if (d[T]==-1) return 0; return 1; } int dfs(int x,int a){ if(x==T||a==0) return a; int f,flow=0; for(int &i=cur[x];i;i=e[i].pre){ int now=e[i].obj; if(d[now]==d[x]+1&&(f=dfs(now,min(a,e[i].flow)))>0){ e[i].flow-=f; e[i^1].flow+=f; flow+=f; a-=f; if(!a) break; } } return flow; } int main() { int x; n=read(); m=read(); S=1; T=n*m; for(int i=1;i<=n;i++) for(int j=1;j<m;j++) {x=read();int v=(i-1)*m+j; add(v,v+1,x);} for(int i=1;i<n;i++) for(int j=1;j<=m;j++) {x=read(); int v=(i-1)*m+j; add(v,v+m,x);} for(int i=1;i<n;i++) for(int j=1;j<m;j++) {x=read(); int v=(i-1)*m+j; add(v,v+m+1,x);} while(bfs()){ for(int i=1;i<=n*m;i++) cur[i]=head[i]; ans=ans+dfs(S,inf); } printf("%lld\n",ans); return 0; }
//法二
#include<bits/stdc++.h> using namespace std; int n,m; #define maxn 2000011 #define maxm 6000011 #define LL long long struct Edge{int to,next,v;}edge[maxm];int first[maxn],le=2; void in(int x,int y,int v) {Edge &e=edge[le];e.to=y;e.v=v;e.next=first[x];first[x]=le++;} void insert(int x,int y,int v) {in(x,y,v);in(y,x,v);} int tot; struct qnode { int id;LL v; bool operator > (const qnode &b) const {return v>b.v;} }; priority_queue<qnode,vector<qnode>,greater<qnode> > q; LL dis[maxn];bool vis[maxn]; LL dijkstra(int s,int t) { for (int i=1;i<=tot;i++) dis[i]=1e18; dis[s]=0; q.push((qnode){s,0}); while (!q.empty()) { const int now=q.top().id; q.pop(); if (vis[now]) continue; vis[now]=1; for (int i=first[now];i;i=edge[i].next) { const Edge &e=edge[i]; if (dis[e.to]>dis[now]+e.v) { dis[e.to]=dis[now]+e.v; q.push((qnode){e.to,dis[e.to]}); } } } return dis[t]; } int main() { scanf("%d%d",&n,&m); if (n==1 || m==1) { if (m==1) swap(n,m); int ans=0x3f3f3f3f; for (int i=1,x;i<m;i++) scanf("%d",&x),ans=min(ans,x); printf("%d\n",ans); return 0; } tot=(n-1)*(m-1)*2+2; int s=tot-1,t=tot; for (int j=1,x;j<m;j++) scanf("%d",&x),insert(t,j,x); for (int i=2;i<=n-1;i++) { int u=(i-1)*(m-1),v=(i-2)*(m-1),w=(n-1)*(m-1); for (int j=1,x;j<m;j++) { scanf("%d",&x); insert(u+j,v+j+w,x); } } for (int j=1,x;j<m;j++) scanf("%d",&x),insert((n-2)*(m-1)+j+(n-1)*(m-1),s,x); for (int i=1,x;i<n;i++) { int w=(n-1)*(m-1),u=(i-1)*(m-1); scanf("%d",&x); insert(s,u+1+w,x); for (int j=2;j<m;j++) { scanf("%d",&x); insert(u+j-1,u+w+j,x); } scanf("%d",&x); insert(t,u+m-1,x); } for (int i=1;i<n;i++) { int u=(i-1)*(m-1),v=(n-1)*(m-1); for (int j=1,x;j<m;j++) { scanf("%d",&x); insert(u+j,u+j+v,x); } } printf("%lld\n",dijkstra(s,t)); return 0; }

1001: [BeiJing2006]狼抓兔子

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 27769  Solved: 7155
[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新加数据一组,可能会卡掉从前可以过的程序。

 

Source

BZOJ1001: [BeiJing2006]狼抓兔子

标签:discus   bsp   ems   ima   信息   get   clu   ret   参与   

原文地址:https://www.cnblogs.com/inamin/p/9035520.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!