【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 }
View Code

 

 

 

posted @ 2014-05-25 22:01  TCtower  阅读(457)  评论(0编辑  收藏  举报