题意:动物要逃跑,工作人员要截断从START(左上角)到END(右下角)的道路,每条边权表示拦截该条道路需要多少工作人员。问最少需要多少人才能完成拦截。
通俗地讲,就是把图一分为二所造成消耗的最小值。
这里用最短路的方法解,主要是因为数据量太大,不能用最小割最大流还处理。
手动画一下这种“割”的形式,发现是从一条边到另一条边,即以边为“点”,在边与边之间见“边”,边上的权值为终点v(其实是一条边)的权值。(本来想直接用点权处理的,可coding的时候发现SPFA中的入队出队操作太繁琐,老老实实改边权了)。这里因为是以边为点,所以要对每条边编号,借用了昨天刚学到的ID()函数,很实用的。
最终的方案是整体从左下到右上,把START与END分成两部分。那么就以最左侧、最下侧的所有点为起点,做一遍最短路,求出最上侧、最右侧边所对应d[]数组的最小值,即为答案。
注:
1、因为是以边为点,共有少于n*m*3个“点”,共要建边(n-1)*(m-1)*2*3条“边”
2、不保证code是正确滴,这道题在uva挂了,难得能一次就跑出样例...偶已经很久木有一次AC了= =
1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<queue> 5 #include<algorithm> 6 #define clr(a,m) memset(a,m,sizeof(a)) 7 #define rep(i,a,b) for(int i=a;i<=b;i++) 8 using namespace std; 9 10 const int MAXN=1111; 11 const int INF =1e9; 12 13 struct Edge{ 14 int v,next,c; 15 Edge(){} 16 Edge(int x,int y,int z):v(x),c(y),next(z){} 17 }edge[MAXN*MAXN*6]; 18 19 int id[MAXN][MAXN][3],num; 20 int grid[MAXN][MAXN][3]; 21 22 int head[MAXN*MAXN*3],tol; 23 int vis[MAXN*MAXN*3],inq[MAXN*MAXN*3],d[MAXN*MAXN*3]; 24 25 void read(int n,int m) 26 { 27 rep(i,1,n) 28 rep(j,1,m-1) 29 scanf("%d",&grid[i][j][0]); 30 rep(i,1,n-1) 31 rep(j,1,m) 32 scanf("%d",&grid[i][j][1]); 33 rep(i,1,n-1) 34 rep(j,1,m-1) 35 scanf("%d",&grid[i][j][2]); 36 } 37 38 void init() 39 { 40 tol=0; 41 clr(head,-1); 42 43 num=0; 44 clr(id,0); 45 } 46 47 void add(int u,int v,int cv,int cu) 48 { 49 edge[tol]=Edge(v,cv,head[u]); 50 head[u]=tol++; 51 52 edge[tol]=Edge(u,cu,head[v]); 53 head[v]=tol++; 54 } 55 56 int ID(int i,int j,int k) 57 { 58 int& x=id[i][j][k]; 59 if(!x)x=++num; 60 return x; 61 } 62 63 void build(int n,int m)//建图:原图在(n-1)*(m-1)个方格中各有两个三角形,在其内部以边为顶点建三角形,共构建(n-1)*(m-1)*2*3条边 64 { 65 init(); 66 rep(i,1,n-1){ 67 rep(j,1,m-1){ 68 add(ID(i,j,0),ID(i,j,2),grid[i][j][2],grid[i][j][0]); 69 add(ID(i,j,0),ID(i,j+1,1),grid[i][j+1][1],grid[i][j][0]); 70 add(ID(i,j,2),ID(i,j+1,1),grid[i][j+1][1],grid[i][j][2]); 71 72 add(ID(i,j,1),ID(i,j,2),grid[i][j][2],grid[i][j][1]); 73 add(ID(i,j,1),ID(i+1,j,0),grid[i+1][j][0],grid[i][j][1]); 74 add(ID(i,j,2),ID(i+1,j,0),grid[i+1][j][0],grid[i][j][2]); 75 } 76 } 77 } 78 79 void SPFA(int n,int m) 80 { 81 priority_queue<int,vector<int>,greater<int> >q; 82 clr(inq,0); 83 rep(i,1,num) 84 d[i]=INF; 85 rep(i,1,n-1){ 86 int s=id[i][1][1]; 87 d[s]=grid[i][1][1]; 88 q.push(s); 89 vis[s]=true; 90 } 91 rep(j,1,m-1){ 92 int s=id[n][j][0]; 93 d[s]=grid[n][j][0]; 94 q.push(s); 95 vis[s]=true; 96 } 97 while(!q.empty()) 98 { 99 int u=q.top();q.pop(); 100 vis[u]=false; 101 for(int i=head[u];i!=-1;i=edge[i].next) 102 { 103 int v=edge[i].v; 104 int c=edge[i].c; 105 if(d[v]>d[u]+c){ 106 d[v]=d[u]+c; 107 if(!vis[v]){ 108 q.push(v); 109 vis[v]=true; 110 } 111 } 112 } 113 } 114 } 115 116 void print(int n,int m,int cnt) 117 { 118 int ans=INF; 119 rep(j,1,m-1) 120 ans=min(ans,d[id[1][j][0]]); 121 rep(i,1,n-1) 122 ans=min(ans,d[id[i][m][1]]); 123 printf("Case %d: Minimum = %d ",cnt,ans); 124 } 125 126 int main() 127 { 128 int n,m,cnt=0; 129 while(scanf("%d%d",&n,&m)==2&&n) 130 { 131 read(n,m); 132 build(n,m); 133 SPFA(n,m); 134 print(n,m,++cnt); 135 } 136 return 0; 137 }