左上角点为(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只狼, 才能完全封锁这条道路,你需要帮助狼王安排一个伏击方案,使得在将兔子一网打尽的前提下,参与的 狼的数量要最小。因为狼还要去找喜羊羊麻烦.
输出一个整数,表示参与伏击的狼的最小数量.
2015.4.16新加数据一组,可能会卡掉从前可以过的程序。
这题第一眼看到觉得是最大流问题。。但是数据很大,不太对?(其实是我不熟悉网络流)
然后的话,这题实际上可以看作一个最短路问题。
推荐论文:两极相通——浅谈最大—最小定理在信息学竞赛中的应 周冬
大概说一下这个例子是如何建图的。
然后我们看到这张图里面分了很多三角块,从左上角的左下三角开始,
标号1,然后第一个矩阵的右上标为2.......大概这样:
然后原点可以看作13,重点看作14.
两个点之间的路径,其实就是通过的边的边权。
比如说8~9,长度是7,5~6是5等等。
至于13和14图片中没有标明,13在左下角,14在右上角。
这两个是原点和终点,我们的目标就是从原点走到终点。
原点和网格图的最左/最下的块相连。比如13连着1,7,9,11。
同理14连着2,4,6,12.
还有一些就是相邻的一些点(如8和7,9,1)他们之间也需要连一条边。
建图的过程有点小麻烦。。不过思考一下就能想通了。
(add的过程是边表加边,由于无向边,所以加两次。heng[][]这种是题目读入的数据)
void build(){ N=(n-1)*(m-1)<<1; Ecnt=0; for (int i=1;i<=N;i++){ int a=i/((m-1)<<1),b=i%((m-1)<<1); if (i&1){ add(i,i+1,xie[a+1][(b>>1)+1]); add(i+1,i,xie[a+1][(b>>1)+1]); if (i+((m-1)<<1)+1<=N) add(i,i+((m-1)<<1)+1,heng[a+2][(b>>1)+1]), add(i+((m-1)<<1)+1,i,heng[a+2][(b>>1)+1]); } else if (b) add(i,i+1,shu[a+1][(b>>1)+1]), add(i+1,i,shu[a+1][(b>>1)+1]); } int tmp; //上面是分出的块内部的关系,下面处理最周边一圈和原点以及终点的关系 start=N+1; end=N+2; for (int i=1;i<=N;i+=(m-1)<<1){ int a=i/((m-1)<<1); add(start,i,shu[a+1][1]); add(i,start,shu[a+1][1]); tmp=i; } for (int i=tmp;i<=N;i+=2){ int a=i%((m-1)<<1); add(start,i,heng[n][(a>>1)+1]); add(i,start,heng[n][(a>>1)+1]); tmp=i; } tmp++; for (int i=tmp;i;i-=(m-1)<<1){ int a=i/((m-1)<<1); add(end,i,shu[a][m]); add(i,end,shu[a][m]); tmp=i; } for (int i=tmp;i;i-=2){ add(end,i,heng[1][i>>1]); add(i,end,heng[1][i>>1]); } }
然后建图完毕后就可以直接跑最短路了。
由于有(n-1)*(m-1)*2+2个节点,2000000,所以可用SPFA或者dij+优先队列。
这个最短路的部分就不说了。。直接跑。。
注意了,此题有个坑。。我掉进去好久。
当n=1 || m=1,我的程序会出点错(由于我建图的打法)
所以这个时候特判就好了。
#include<bits/stdc++.h> using namespace std; int n,m,N,Ecnt,dis[6000005]; bool vis[6000005]; int start,end; struct Edge{ int next,to,val; }ty[6000005]; int head[6000005]; struct Heap{ int num,val; }; #define qq(a,b) (Heap){a,b} priority_queue<Heap,vector<Heap> >Q; void add(int u,int v,int w){ ty[++Ecnt].next=head[u]; ty[Ecnt].to=v; ty[Ecnt].val=w; head[u]=Ecnt; } int heng[1005][1005],shu[1005][1005],xie[1005][1005]; void tyread(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<m;j++) scanf("%d",&heng[i][j]); for (int i=1;i<n;i++) for (int j=1;j<=m;j++) scanf("%d",&shu[i][j]); for (int i=1;i<n;i++) for (int j=1;j<m;j++) scanf("%d",&xie[i][j]); } void build(){ N=(n-1)*(m-1)<<1; Ecnt=0; for (int i=1;i<=N;i++){ int a=i/((m-1)<<1),b=i%((m-1)<<1); if (i&1){ add(i,i+1,xie[a+1][(b>>1)+1]); add(i+1,i,xie[a+1][(b>>1)+1]); if (i+((m-1)<<1)+1<=N) add(i,i+((m-1)<<1)+1,heng[a+2][(b>>1)+1]), add(i+((m-1)<<1)+1,i,heng[a+2][(b>>1)+1]); } else if (b) add(i,i+1,shu[a+1][(b>>1)+1]), add(i+1,i,shu[a+1][(b>>1)+1]); } int tmp; start=N+1; end=N+2; for (int i=1;i<=N;i+=(m-1)<<1){ int a=i/((m-1)<<1); add(start,i,shu[a+1][1]); add(i,start,shu[a+1][1]); tmp=i; } for (int i=tmp;i<=N;i+=2){ int a=i%((m-1)<<1); add(start,i,heng[n][(a>>1)+1]); add(i,start,heng[n][(a>>1)+1]); tmp=i; } tmp++; for (int i=tmp;i;i-=(m-1)<<1){ int a=i/((m-1)<<1); add(end,i,shu[a][m]); add(i,end,shu[a][m]); tmp=i; } for (int i=tmp;i;i-=2){ add(end,i,heng[1][i>>1]); add(i,end,heng[1][i>>1]); } } bool operator<(Heap x,Heap y){ return x.val>y.val; } void dijkstra(int s,int t){ memset(vis,0,sizeof(vis)); memset(dis,60,sizeof(dis)); dis[s]=0; Q.push(qq(s,0)); while ((!Q.empty())){ Heap mi=Q.top(); Q.pop(); if (vis[mi.num]) continue; vis[mi.num]=1; for (int j=head[mi.num];j;j=ty[j].next){ int q=ty[j].to; if (vis[q]) continue; int w=ty[j].val; if (w+mi.val<dis[q]){ dis[q]=w+mi.val; Q.push(qq(q,dis[q])); } } } } int main(){ tyread(); if (n==1 || m==1){ int ans=1e9; if (n==1){ for (int j=1;j<m;j++) ans=min(ans,heng[1][j]); printf("%d\n",ans); } else{ for (int i=1;i<n;i++) ans=min(ans,shu[i][1]); printf("%d\n",ans); } return 0; } build(); dijkstra(start,end); printf("%d\n",dis[end]); return 0; }