此题为基本的KM匹配题目,在Hdu做的时候是在网络流专题里面,所以用最小费用最大流做了一下。这也是我第一次写最小费用最大流算法。 其中第一次为了采用标号法,使用dijkstra最短路来拓展增广路径,其中为了避免负权情况采用了一下策略: 将 G中有流边(f(e)>0)的权w(e)修正为0。为此, 每次在增流网络上求得最短路径后,以下式计算G中新的边权w " (u,v):
w " (u,v)=L(u)-L(v)+w(u,v) (*)
式中 L(u),L(v) -- 计算G′的x至y最短路径时u和v的标号值。第一次求最短径时如果(u,v)是增流路径上的边, 则据最短 路径算法一定有 L(v)=L(u)+w ' (u,v)=L(u)+w(u,v), 代入(*)式必有
w″(u,v)=0。
如果(u,v)不是增流路径上的边,则一定有: L(v)≤L(u)+w(u,v), 代入(*)式则有 w(u,v)≥0。
可见第一次修正w(e)后,对任一边,皆有w(e)≥0, 且有流 的边(增流链上的边),一定有w(e)=0。以后每次迭代计算,若 f(u,v)>0,增流网络需建立(v,u)边,边权数w ' (v,u)=-w(u,v) =0,即不会再出现负权边。 此外,每次迭代计算用(*)式修正一切w(e), 不难证明对每一条x至y的路径而言,其路径长度都同样增加L(x)-L(y)。因此,x至y的最短路径不会因对w(e)的修正而发生变化。
可是很悲剧的是,虽然我过了很多大数据,而且在POJ上面顺利的AC了。可惜当我提交的hduOJ上面的时候却WA了。。。。
检查了好久也没发现错误,很崩溃。。。。代码如下:
1#include "stdio.h" 2#include "string.h" 3#include "math.h" 4#define N 500 5#define INF 100000000 6struct Nod 7{ 8 int r; 9 int c; 10}; 11struct Edge 12{ 13 int w; 14 int c; 15}; 16Nod hou[N]; 17Nod man[N]; 18Edge c[N][N]; 19char grid[N][N]; 20int Row,Col,n,sc,sk; 21int d[N],s[N]; 22int augc; 23int flow; 24bool flag[N]; 25 26void Map() 27{ 28 int i,j; 29 for(i=0;i<n;i++) 30 { 31 for(j=0;j<n;j++) 32 { 33 if(c[i][j].c>0) 34 { 35 if(c[i][j].w==INF) 36 c[i][j].w=0; 37 else 38 c[i][j].w=d[i]+c[i][j].w-d[j]; 39 } 40 } 41 } 42} 43 44bool Dij() 45{ 46 int i,j,minDis,u; 47 for(i=0;i<n;i++) 48 { 49 if(c[sc][i].c>0) 50 d[i]=c[sc][i].w; 51 else d[i]=INF; 52 s[i]=0; 53 } 54 d[sc]=0; 55 s[sc]=1; 56 for(i=0;i<n;i++) 57 { 58 minDis=INF; 59 for(j=0;j<n;j++) 60 { 61 if(s[j]==0 && d[j]<minDis) 62 { 63 u=j; 64 minDis=d[j]; 65 } 66 } 67 if(minDis==INF) 68 { 69 if(d[sk]<INF) return true; 70 else return false; 71 } 72 s[u]=1; 73 for(j=0;j<n;j++) 74 { 75 if((s[j]==0) && (c[u][j].w<INF) && (c[u][j].c>0) && (d[u]+c[u][j].w<d[j])) 76 { 77 d[j]=d[u]+c[u][j].w; 78 } 79 } 80 } 81 if(d[sk]<INF) return true; 82 else return false; 83} 84 85bool aug(int v) 86{ 87 int i,augco; 88 augco=augc; 89 flag[v]=true; 90 if(v==sk) 91 { 92 flow+=augc; 93 return true; 94 } 95 for(i=1;i<n;i++) 96 { 97 if((c[v][i].c>0)&&(!flag[i])) 98 { 99 if(d[i]==d[v]+c[v][i].w) 100 { 101 if(c[v][i].c<augc) 102 augc=c[v][i].c; 103 if(aug(i)) 104 { 105 c[v][i].c-=augc; 106 c[i][v].c+=augc; 107 return true; 108 } 109 augc=augco; 110 } 111 } 112 } 113 return false; 114} 115void Print() 116{ 117 int i,j; 118 int tem; 119 for(i=0;i<n;i++) 120 { 121 for(j=0;j<n;j++) 122 { 123 tem=c[i][j].w; 124 if(tem==INF) tem=-1; 125 printf("%d(%d) ",c[i][j].c,tem); 126 } 127 printf("\n"); 128 } 129} 130void MSMF() 131{ 132 int ans=0; 133 flow=0; 134 int tem=0; 135 while(1) 136 { 137 if(!Dij()) break; 138 ans+=tem+d[sk]; 139 tem+=d[sk]; 140 augc=INF; 141 memset(flag,false,sizeof(flag)); 142 if(!aug(sc))break; 143 Map(); 144 // Print(); 145 } 146 printf("%d\n",ans); 147} 148int main() 149{ 150 int i,j,mn,hn,t; 151 while(scanf("%d %d",&Row,&Col)!=EOF) 152 { 153 if(!Row && !Col) break; 154 for(i=0;i<Row;i++) 155 { 156 scanf("%s",grid[i]); 157 } 158 mn=1; 159 hn=1; 160 sc=0; 161 for(i=0;i<Row;i++) 162 { 163 for(j=0;j<Col;j++) 164 { 165 if(grid[i][j]=='H') 166 { 167 hou[hn].r=i+1; 168 hou[hn++].c=j+1; 169 } 170 else if(grid[i][j]=='m') 171 { 172 man[mn].r=i+1; 173 man[mn++].c=j+1; 174 } 175 } 176 } 177 if(mn!=hn) 178 { 179 printf("0\n"); 180 continue; 181 } 182 t=mn-1; 183 n=2*t+2; 184 for(i=0;i<n;i++) 185 { 186 for(j=0;j<n;j++) 187 { 188 c[i][j].w=INF; 189 c[i][j].c=0; 190 } 191 } 192 sk=n-1; 193 for(i=1;i<=t;i++) 194 { 195 c[sc][i].w=0; 196 c[sc][i].c=1; 197 c[i+t][sk].w=0; 198 c[i+t][sk].c=1; 199 } 200 for(i=1;i<=t;i++) 201 { 202 for(j=1;j<=t;j++) 203 { 204 c[i][j+t].w=abs(man[i].r-hou[j].r)+abs(man[i].c-hou[j].c); 205 c[i][j+t].c=1; 206 } 207 } 208 // Print(); 209 MSMF(); 210 } 211 return 0; 212} 213
WA了之后肯定是很无奈,也很郁闷,所以决定采用SPFA来扩展找增广路,于是我拿出自己的SPFA模板,很快就改好了,结果很顺利的在hduoj上面AC了。。。。代码如下:
1#include "stdio.h" 2#include "string.h" 3#include "math.h" 4#define N 250 5#define INF 1000000000 6struct Nod 7{ 8 int r; 9 int c; 10}; 11struct Edge 12{ 13 int w; 14 int c; 15}; 16Nod hou[N]; 17Nod man[N]; 18Edge c[N][N]; 19char grid[N][N]; 20bool flag[N]; 21int Row,Col,n,sc,sk; 22int d[N],s[N]; 23int augc; 24int flow; 25 26int stk[30000000]; 27int vst[N]; 28 29bool SPFA() 30{ 31 int i,p,top; 32 top=0; 33 stk[top++]=0; 34 memset(vst,false,sizeof(vst)); 35 for(i=0;i<n;i++) d[i]=INF; 36 d[0]=0; 37 vst[0]=true; 38 while(top) 39 { 40 p=stk[--top]; 41 vst[p]=false; 42 for(i=0;i<n;i++) 43 { 44 if((c[p][i].c>0) && (c[p][i].w!=INF) && (d[i]-d[p]>c[p][i].w)) 45 { 46 d[i]=d[p]+c[p][i].w; 47 if(!vst[i]) 48 { 49 stk[top++]=i; 50 vst[i]=true; 51 } 52 } 53 } 54 } 55 if(d[sk]<INF) 56 return true; 57 else return false; 58} 59bool aug(int v) 60{ 61 int i,augco; 62 augco=augc; 63 flag[v]=true; 64 if(v==sk) 65 { 66 flow+=augc; 67 return true; 68 } 69 for(i=0;i<n;i++) 70 { 71 if((c[v][i].c>0)&&(!flag[i])) 72 { 73 if(d[i]==d[v]+c[v][i].w) 74 { 75 if(c[v][i].c<augc) 76 augc=c[v][i].c; 77 if(aug(i)) 78 { 79 c[v][i].c-=augc; 80 c[i][v].c+=augc; 81 c[i][v].w=-c[v][i].w; 82 return true; 83 } 84 augc=augco; 85 } 86 } 87 } 88 return false; 89} 90void MSMF() 91{ 92 int ans=0; 93 flow=0; 94 while(1) 95 { 96 if(!SPFA()) break; 97 ans+=d[sk]; 98 augc=INF; 99 memset(flag,false,sizeof(flag)); 100 if(!aug(sc))break; 101 } 102 printf("%d\n",ans); 103} 104int main() 105{ 106 int i,j,mn,hn,t,tem; 107 while(scanf("%d %d",&Row,&Col)!=EOF) 108 { 109 if(!Row && !Col) break; 110 for(i=0;i<Row;i++) 111 { 112 scanf("%s",grid[i]); 113 } 114 mn=1; 115 hn=1; 116 sc=0; 117 for(i=0;i<Row;i++) 118 { 119 for(j=0;j<Col;j++) 120 { 121 if(grid[i][j]=='H') 122 { 123 hou[hn].r=i+1; 124 hou[hn++].c=j+1; 125 } 126 else if(grid[i][j]=='m') 127 { 128 man[mn].r=i+1; 129 man[mn++].c=j+1; 130 } 131 } 132 } 133 if(mn!=hn) 134 { 135 printf("0\n"); 136 continue; 137 } 138 t=mn-1; 139 n=2*t+2; 140 for(i=0;i<n;i++) 141 { 142 for(j=0;j<n;j++) 143 { 144 c[i][j].w=INF; 145 c[i][j].c=0; 146 } 147 } 148 sk=n-1; 149 for(i=1;i<=t;i++) 150 { 151 c[sc][i].w=0; 152 c[sc][i].c=1; 153 c[i+t][sk].w=0; 154 c[i+t][sk].c=1; 155 } 156 for(i=1;i<=t;i++) 157 { 158 for(j=1;j<=t;j++) 159 { 160 tem=man[i].r-hou[j].r; 161 if(tem<0)tem=-tem; 162 c[i][j+t].w=tem; 163 tem=man[i].c-hou[j].c; 164 if(tem<0) tem=-tem; 165 c[i][j+t].w+=tem; 166 c[i][j+t].c=1; 167 } 168 } 169 MSMF(); 170 } 171 return 0; 172}
那么为什么呢?经过仔细的重新查看算法步骤,发现33-39行的更新不是很完备,对于c[i][j]==0时应该也进行同样的权值更变,以保证任何一条路径的值增加为lx[]-ly[];更正后果然,顺利ac了。
|
|
|
| 日 | 一 | 二 | 三 | 四 | 五 | 六 |
---|
24 | 25 | 26 | 27 | 28 | 29 | 30 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 1 | 2 | 3 | 4 |
|
导航
统计
常用链接
留言簿
随笔分类(1)
随笔档案(2)
文章分类(15)
文章档案(7)
搜索
最新评论
阅读排行榜
评论排行榜
|
|