【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
【输出格式】
输出一个整数,表示参与伏击的狼的最小数量.
【分析】
看一眼就知道这一道典型的最小割问题,但是数据太大了,传统解法会导致超时。
我才知道有平面图最小割转最短路的方法==。(参见2008年周冬神牛论文)
尼玛以后邻接表加边再也不用LRJ的了,害得我MLE了无数次......
1 #include <cstdlib> 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5 #include <cmath> 6 #include <vector> 7 #include <queue> 8 const int Max=1001*1001*2;//最大点个数 9 const int INF=~0U>>2; 10 using namespace std; 11 //边结构体 12 struct edge{int to,w;}; 13 struct node 14 { 15 int dist,num; 16 //按照距离大小排序 17 bool operator <(const node &b)const 18 { 19 return dist>b.dist; 20 } 21 }; 22 int s,t,n,m;//源汇点 23 int dist[Max]; 24 vector<edge>G[Max]; 25 priority_queue<node>Q; 26 27 void init(); 28 void AddEdge(int u,int v,int w); 29 int dijkstra(int sta); 30 31 int main() 32 { 33 //文件操作 34 //freopen("data.txt","r",stdin); 35 //freopen("me.out","w",stdout); 36 37 init();//读入数据 38 //for (int i=0;i<G[13].size();i++) printf("%d \n",Edges[G[13][i]].w); 39 40 printf("%d\n",dijkstra(s)); 41 return 0; 42 } 43 //读入+建图 44 void init() 45 { 46 int i,j; 47 //读入长宽,共有(n-1)*(m-1)*2个顶点 48 scanf("%d%d",&n,&m); 49 s=0;t=(n-1)*(m-1)*2+1;//设定源汇点 50 //一行总共有2*(m-1)个节点 51 for (i=1;i<=n;i++)//读入横边 52 for (j=1;j<m;j++) 53 { 54 int w; 55 scanf("%d",&w); 56 if (i==1) AddEdge(j*2,t,w);//连最上面的点与汇点 57 else if (i==n) AddEdge((i-2)*2*(m-1)+2*j-1,s,w);//最下面的点与源点相连 58 else AddEdge((i-2)*2*(m-1)+2*j-1,(i-1)*2*(m-1)+2*j,w);//上下顶点相连 59 } 60 for (i=1;i<n;i++)//读竖边 61 for (j=1;j<=m;j++) 62 { 63 int w; 64 scanf("%d",&w); 65 if (j==1) AddEdge((i-1)*2*(m-1)+2*j-1,s,w);//最左边的连源点 66 else if (j==m) AddEdge((i-1)*2*(m-1)+2*(j-1),t,w);//最右边的连汇点 67 else AddEdge((i-1)*2*(m-1)+2*(j-1),(i-1)*2*(m-1)+2*j-1,w);//竖边左右相连 68 } 69 for (i=1;i<n;i++)//读对角线 70 for (j=1;j<m;j++) 71 { 72 int w; 73 scanf("%d",&w); 74 AddEdge((i-1)*2*(m-1)+2*j-1,(i-1)*2*(m-1)+2*j,w);//对角线加边 75 } 76 return; 77 } 78 //加无向边 79 void AddEdge(int u,int v,int w) 80 { 81 G[u].push_back((edge){v,w}); 82 G[v].push_back((edge){u,w}); 83 } 84 int dijkstra(int sta) 85 { 86 int i; 87 for (i=0;i<=t;i++) 88 dist[i]=INF; 89 90 Q.push((node){0,s}); 91 while(Q.size()) 92 { 93 node u=Q.top();Q.pop();if(u.dist>dist[u.num])continue; 94 if(u.num==t) return u.dist; 95 for (i=0;i<G[u.num].size();i++) 96 { 97 int ncost=u.dist+G[u.num][i].w; 98 if(ncost<dist[G[u.num][i].to]) 99 { 100 dist[G[u.num][i].to]=ncost; 101 Q.push((node){ncost,G[u.num][i].to}); 102 } 103 } 104 } 105 }