首页 > 代码库 > bzoj1001 [BeiJing2006]狼抓兔子
bzoj1001 [BeiJing2006]狼抓兔子
1001: [BeiJing2006]狼抓兔子
Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 12749 Solved: 3027
[Submit][Status][Discuss]
Description
现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形:
<iframe id="iframe_0.585232120747647" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22http://www.lydsy.com/JudgeOnline/images/1001.jpg?_=4634143%22%20style=%22border:none;max-width:696px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById(‘img‘);%20window.parent.postMessage(%7BiframeId:‘iframe_0.585232120747647‘,width:img.width,height:img.height%7D,%20‘http://www.cnblogs.com‘);%7D%3C/script%3E" frameborder="0" scrolling="no" width="320" height="240"></iframe>
左上角点为(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
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
HINT
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
Source
其实dinic可以过
flag 今天起手写循环队列
#include<cstdio>#include<cstring>#include<queue>#include<cstdlib> #define MAXN 1000005#define INF 0x3f3f3f3fusing namespace std; struct Edge{ int v,next,val;};Edge edge[6*MAXN]; int ggd=INF;int cycle,n,m,x,now,head[MAXN*6],s,t,dist[MAXN*6],vis[MAXN*6]; void addEdge(int u,int v,int val){ now++; edge[now].v=v; edge[now].next=head[u]; edge[now].val=val; head[u]=now;} void init1(){ for (int i=1;i<=n;i++) for (int j=1;j<=m-1;j++) { scanf("%d",&x),ggd=min(ggd,x); if (i==1) { addEdge(t,(i-1)*cycle+j*2,x); addEdge((i-1)*cycle+j*2,t,x); } else if (i==n) { addEdge((i-2)*cycle+j*2-1,s,x); addEdge(s,(i-2)*cycle+j*2-1,x); } else { addEdge((i-2)*cycle+j*2-1,(i-1)*cycle+j*2,x); addEdge((i-1)*cycle+j*2,(i-2)*cycle+j*2-1,x); } }} void init2(){ for (int i=1;i<=n-1;i++) for (int j=1;j<=m;j++) { scanf("%d",&x),ggd=min(ggd,x); if (j==1) { addEdge(s,(i-1)*cycle+1,x); addEdge((i-1)*cycle+1,s,x); } else if (j==m) { addEdge(i*cycle,t,x); addEdge(t,i*cycle,x); } else { addEdge((i-1)*cycle+j*2-2,(i-1)*cycle+j*2-1,x); addEdge((i-1)*cycle+j*2-1,(i-1)*cycle+j*2-2,x); } } } void init3(){ int tot=-1; for (int i=1;i<=n-1;i++) for (int j=1;j<=m-1;j++) { scanf("%d",&x); tot+=2,ggd=min(ggd,x); addEdge(tot,tot+1,x); addEdge(tot+1,tot,x); }} void init(){ scanf("%d %d",&n,&m); cycle=(m-1)*2; s=(n-1)*(m-1)*2+1,t=s+1; init1(); init2(); init3(); if(n==1||m==1){ printf("%d",ggd); exit(0); }} struct state{ int num,nowVal; state() {} state(int _num,int _nowVal):num(_num),nowVal(_nowVal) {} friend bool operator < (state a,state b) { return a.nowVal>b.nowVal; }}; priority_queue q; int Dijkstra(){ memset(dist,INF,sizeof(dist)); q.push(state(s,0)); dist[s]=0,vis[s]=0; while (q.size()) { state temp=q.top(); q.pop(); if (temp.nowVal>dist[temp.num]) continue; if (temp.num==t) return dist[t]; for (int x=head[temp.num];x!=0;x=edge[x].next) { if (dist[temp.num]+edge[x].val { dist[edge[x].v]=dist[temp.num]+edge[x].val; q.push(state(edge[x].v,dist[edge[x].v])); } } } return -1;} int main(){ init(); printf("%d",Dijkstra()); return 0;}
也可以对偶图+spfa
用切遍的代价为权值建图,最后联向超级源点和超级汇点
#include<iostream>#include<cstring>#include<cstdio>using namespace std;int n,m;int num;struct data{int v,next,w;}edge[6000001];int dis[1000001];int head[1000001],q[1000001],ans;void add_edge(int u,int v,int w){ num++; edge[num].v=v;edge[num].w=w;edge[num].next=dis[u];dis[u]=num;}bool bfs(){ int now,i; memset(head,-1,sizeof(head)); int t=0,w=1; q[t]=1;head[1]=0; while(t<w) { now=q[t];t++; i=dis[now]; for(int i=dis[now];i;i=edge[i].next) { if(edge[i].w&&head[edge[i].v]<0) { q[w++]=edge[i].v; head[edge[i].v]=head[now]+1; } } } if(head[n*m]==-1)return 0; return 1;}int dfs(int x,int f){ if(x==n*m)return f; int i=dis[x]; int w,used=0; while(i) { if(edge[i].v&&head[edge[i].v]==head[x]+1) { w=f-used; w=dfs(edge[i].v,min(w,edge[i].w)); edge[i].w-=w; edge[i+1].w+=w; used+=w; if(used==f)return f; } i=edge[i].next; } if(!used)head[x]=-1; return used;}void dinic(){ while(bfs())ans+=dfs(1,0x7fffffff);}inline void init1(){ int x; for(int i=1;i<=n;i++) for(int j=1;j<m;j++) { scanf("%d",&x); add_edge(m*(i-1)+j,m*(i-1)+j+1,x); add_edge(m*(i-1)+j+1,m*(i-1)+j,x); }}inline void init2(){ int x; for(int i=1;i<n;i++) for(int j=1;j<=m;j++) { scanf("%d",&x); add_edge(m*(i-1)+j,m*(i)+j,x); add_edge(m*(i)+j,m*(i-1)+j,x); }}inline void init3(){ int x; for(int i=1;i<n;i++) for(int j=1;j<m;j++) { scanf("%d",&x); add_edge(m*(i-1)+j,m*(i)+j+1,x); add_edge(m*(i)+j+1,m*(i-1)+j,x); }}inline void init(){ init1(); init2(); init3();}int main(){ scanf("%d%d",&n,&m); init(); dinic(); printf("%d\n",ans); return 0;}
bzoj1001 [BeiJing2006]狼抓兔子