http://poj.org/problem?id=2195
第一个最佳匹配的题.可耻的模板都不会套。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <algorithm> 5 using namespace std; 6 7 const int maxn = 2000 + 10; 8 9 const int INF = 0x7fffffff; 10 11 int n,m; 12 int W[maxn][maxn]; //存储权值 13 int Lx[maxn], Ly[maxn]; // 顶标 14 int left[maxn]; // left[i]为右边第i个点的匹配点编号 15 bool S[maxn], T[maxn]; // S[i]和T[i]为左/右第i个点是否已标记 16 17 18 bool match(int i){ 19 S[i] = true; 20 for(int j = 1; j <= m; j++) if (Lx[i]+Ly[j]==W[i][j] && !T[j]) 21 { 22 T[j] = true; 23 if (!left[j] || match(left[j])) 24 { 25 left[j] = i; 26 return true; 27 } 28 } 29 return false; 30 } 31 32 void update(){ 33 int a = INF; 34 for(int i = 1; i <= n; i++) if(S[i]) 35 for(int j = 1; j <= m; j++) if(!T[j]) 36 a = min(a, W[i][j]-Lx[i]-Ly[j]); //若是最大权匹配则Lx[i]+Ly[j]-W[i][j]; 同样是取最小值 37 for(int i = 1; i <= n; i++) { 38 if(S[i]) Lx[i] -= a; 39 if(T[i]) Ly[i] += a; 40 } 41 } 42 43 void KM() { 44 for(int i = 1; i <= n; i++) { 45 left[i] = Lx[i] = Ly[i] = 0; 46 for(int j = 1; j <= m; j++) 47 Lx[i] = min(Lx[i], W[i][j]); //若是最大权匹配.则初始值顶标取最大值,最小匹配则去最小值 48 } 49 for(int i = 1; i <= n; i++) { 50 for(;;) { 51 for(int j = 1; j <= m; j++) S[j] = T[j] = 0; 52 if(match(i)) break; else update(); 53 } 54 } 55 } 56 char s[305]; 57 struct point 58 { 59 int x,y; 60 }; 61 point man[305],house[305]; 62 int main(){ 63 //freopen("a.txt","r",stdin); 64 int sum,man_num,house_num; 65 while(scanf("%d%d",&n,&m)!=EOF&&(n+m)) 66 { 67 int i,j; 68 man_num=1,house_num=1; 69 for(int i=1;i<=n;i++) 70 { 71 scanf("%s",s+1); 72 for(int j=1;j<=m;j++) 73 { 74 if(s[j]==‘m‘) 75 { 76 man[man_num].x=i; 77 man[man_num++].y=j; 78 } 79 else if(s[j]==‘H‘) 80 { 81 house[house_num].x=i; 82 house[house_num++].y=j; 83 } 84 } 85 } 86 man_num--,house_num--; 87 // printf("%d %d\n",man_num,house_num); 88 n=man_num;m=house_num; 89 for(int i=1;i<=man_num;i++) 90 for(int j=1;j<=house_num;j++) 91 W[i][j]=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y); 92 sum=0; 93 KM(); // 最大权匹配 94 for(i=1;i<=m;i++) 95 sum+=W[left[i]][i]; 96 printf("%d\n",sum); 97 } 98 //for(int i = 1; i <= n; i++) printf("left[%d]=%d\n", i,left[i]); 99 //getch(); 100 return 0; 101 }
当然还可以用费用流来做.
算出每一个到每一个房子的距离后建图。
源点与人连,容量1,费用0
人与每个房子都要连,容量1,费用为距离
每个房子与汇点连,容量1,费用0
求一次最小费用即可
另外此题数据的范围开大点。
Bellmanford:
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<vector> 5 #include<algorithm> 6 #include<cassert> 7 using namespace std; 8 9 const int maxn = 2000 + 20; 10 const int INF = 1000000000; 11 12 struct Edge 13 { 14 int from, to, cap, flow, cost; 15 Edge(int u, int v, int c, int f, int w):from(u),to(v),cap(c),flow(f),cost(w) {} 16 }; 17 18 struct MCMF 19 { 20 int n, m; 21 vector<Edge> edges; 22 vector<int> G[maxn]; 23 int inq[maxn]; // 是否在队列中 24 int d[maxn]; // Bellman-Ford 25 int p[maxn]; // 上一条弧 26 int a[maxn]; // 可改进量 27 28 void init(int n) 29 { 30 this->n = n; 31 for(int i = 0; i < n; i++) G[i].clear(); 32 edges.clear(); 33 } 34 35 void AddEdge(int from, int to, int cap, int cost) 36 { 37 edges.push_back(Edge(from, to, cap, 0, cost)); 38 edges.push_back(Edge(to, from, 0, 0, -cost)); 39 m = edges.size(); 40 G[from].push_back(m-2); 41 G[to].push_back(m-1); 42 } 43 44 bool BellmanFord(int s, int t, int flow_limit, int& flow, int& cost) 45 { 46 for(int i = 0; i < n; i++) d[i] = INF; 47 memset(inq, 0, sizeof(inq)); 48 d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; 49 50 queue<int> Q; 51 Q.push(s); 52 while(!Q.empty()) 53 { 54 int u = Q.front(); Q.pop(); 55 inq[u] = 0; 56 for(int i = 0; i < G[u].size(); i++) 57 { 58 Edge& e = edges[G[u][i]]; 59 if(e.cap > e.flow && d[e.to] > d[u] + e.cost) 60 { 61 d[e.to] = d[u] + e.cost; 62 p[e.to] = G[u][i]; 63 a[e.to] = min(a[u], e.cap - e.flow); 64 if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; } 65 } 66 } 67 } 68 if(d[t] == INF) return false; 69 if(flow + a[t] > flow_limit) a[t] = flow_limit - flow; 70 flow += a[t]; 71 cost += d[t] * a[t]; 72 for(int u = t; u != s; u = edges[p[u]].from) 73 { 74 edges[p[u]].flow += a[t]; 75 edges[p[u]^1].flow -= a[t]; 76 } 77 return true; 78 } 79 80 // 需要保证初始网络中没有负权圈 81 int MincostFlow(int s, int t, int flow_limit, int& cost) 82 { 83 int flow = 0; cost = 0; 84 while(flow < flow_limit && BellmanFord(s, t, flow_limit, flow, cost)); 85 return flow; 86 } 87 88 }; 89 90 MCMF g; 91 typedef struct{ 92 int x,y; 93 }Point; 94 95 Point man[maxn],home[maxn]; 96 int man_sum,home_sum; 97 98 99 int main() 100 { 101 int n,m,i,j; 102 char s[maxn]; 103 while(~scanf("%d%d",&n,&m) && n || m) 104 { 105 getchar(); 106 man_sum=home_sum=1; 107 for(i=1;i<=n;i++) 108 { //记录下人与房子的坐标 109 gets(s); 110 for(j=0;j<m;j++) 111 { 112 if(s[j]==‘m‘) 113 { 114 man[man_sum].x=i; 115 man[man_sum++].y=j+1; 116 } 117 if(s[j]==‘H‘) 118 { 119 home[home_sum].x=i; 120 home[home_sum++].y=j+1; 121 } 122 } 123 } 124 man_sum--; home_sum--; 125 g.init(man_sum+home_sum+2); 126 127 for(i=1;i<=man_sum;i++) g.AddEdge(0, i, 1, 0); //源点指向人 128 129 for(i=1;i<=man_sum;i++) //人指向房子 130 { 131 for(j=man_sum+1;j<=man_sum+home_sum;j++) 132 { 133 g.AddEdge(i, j, 1, abs(man[i].x-home[j-man_sum].x)+abs(man[i].y-home[j-man_sum].y)); 134 } 135 } 136 137 for(i=man_sum+1;i<=man_sum+home_sum;i++) g.AddEdge(i, man_sum+home_sum+1, 1, 0); //房子指向汇点 138 139 int cost; 140 g.MincostFlow(0, man_sum+home_sum+1, man_sum, cost); 141 printf("%d\n", cost); 142 } 143 return 0; 144 }
SPFA:
参考:http://blog.csdn.net/lenleaves/article/details/7904588
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<string> 5 #include<queue> 6 #include<cmath> 7 #include<cstdio> 8 9 using namespace std; 10 11 #define MAXN 2000 12 #define MAXM 110000 13 #define INF 0x3FFFFFF 14 15 struct edge 16 { 17 int to,c,w,next; 18 }; 19 20 edge e[MAXM]; 21 bool in[MAXN]; 22 int hx[500],hy[500],mx[500],my[500]; 23 int head[MAXN],dis[MAXN],pre[MAXN],en,maxflow,mincost; 24 int vn,st,ed,r,c,hn,mn; 25 26 void add(int a,int b,int c,int d) 27 { 28 e[en].to=b; 29 e[en].c=c; 30 e[en].w=d; 31 e[en].next=head[a]; 32 head[a]=en++; 33 e[en].to=a; 34 e[en].c=0; 35 e[en].w=-d; 36 e[en].next=head[b]; 37 head[b]=en++; 38 } 39 40 bool spfa(int s) 41 { 42 queue<int> q; 43 for(int i=0;i<=vn;i++) 44 { 45 dis[i]=INF; 46 in[i]=false; 47 pre[i]=-1; 48 } 49 dis[s]=0; 50 in[s]=true; 51 q.push(s); 52 while(!q.empty()) 53 { 54 int tag=q.front(); 55 in[tag]=false; 56 q.pop(); 57 for(int i=head[tag];i!=-1;i=e[i].next) 58 { 59 int j=e[i].to; 60 if(e[i].w+dis[tag]<dis[j] && e[i].c) 61 { 62 dis[j]=e[i].w+dis[tag]; 63 pre[j]=i; 64 if(!in[j]) 65 { 66 q.push(j); 67 in[j]=true; 68 } 69 } 70 } 71 } 72 if(dis[ed]==INF) 73 return false; 74 return true; 75 } 76 77 void update() 78 { 79 int flow=INF; 80 for (int i=pre[ed];i!=-1;i=pre[e[i^1].to]) 81 if(e[i].c<flow) flow=e[i].c; 82 for (int i=pre[ed];i!=-1;i=pre[e[i^1].to]) 83 { 84 e[i].c-=flow,e[i^1].c+=flow; 85 } 86 maxflow+=flow; 87 mincost+=flow*dis[ed]; 88 } 89 90 void mincostmaxflow() 91 { 92 maxflow=0,mincost=0; 93 while(spfa(st)) 94 update(); 95 } 96 97 void solve() 98 { 99 char s[500]; 100 hn=0,mn=0,en=0; 101 memset(head,-1,sizeof(head)); 102 for(int i=1;i<=r;i++) 103 { 104 scanf("%s",s); 105 for(int j=0;j<c;j++) 106 { 107 if(s[j]==‘m‘) mx[mn]=i,my[mn++]=j+1; 108 if(s[j]==‘H‘) hx[hn]=i,hy[hn++]=j+1; 109 } 110 } 111 vn=mn+hn+5; 112 st=0,ed=mn+hn+1; 113 for(int i=0;i<mn;i++) 114 for(int j=0;j<hn;j++) 115 { 116 int dist=abs(mx[i]-hx[j])+abs(my[i]-hy[j]); 117 add(i+1,j+1+mn,1,dist); 118 } 119 for(int i=0;i<mn;i++) 120 add(st,i+1,1,0); 121 for(int i=0;i<hn;i++) 122 add(i+1+mn,ed,1,0); 123 mincostmaxflow(); 124 printf("%d\n",mincost); 125 } 126 127 int main() 128 { 129 while(scanf("%d%d",&r,&c)!=EOF && r+c) 130 solve(); 131 return 0; 132 }
时间: 2024-11-08 23:38:50