poj - 2195 Going Home (费用流 || 最佳匹配)

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

poj - 2195 Going Home (费用流 || 最佳匹配)的相关文章

POJ 3680 Intervals 离散 + 费用流

Intervals Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 6246   Accepted: 2542 Description You are given N weighted open intervals. The ith interval covers (ai, bi) and weighs wi. Your task is to pick some of the intervals to maximize t

POJ 2175 Evacuation Plan 费用流 负圈定理

题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在负环上. 2.这个负环可能包括汇点t,所以构建残量网络的时候也要考虑防空洞到t上的容量. //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring

poj 2195 Going Home 二分图最小权匹配KM算法

题意: 有n个人要回到n间房子里,每间房子只允许一个人,求n个人要走的最小距离和. 分析: 裸的二分图最小权匹配,KM搞之. 代码: //poj 2195 //sep9 #include <iostream> using namespace std; const int maxN=128; char g[maxN][maxN]; int mx[maxN],my[maxN],hx[maxN],hy[maxN]; int w[maxN][maxN]; int lx[maxN],ly[maxN],l

POJ 3670 Intervals(费用流)

POJ 3680 Intervals 题目链接 题意:给定一些区间,每个区间有一个权值,要求用这些区间去覆盖,每个点最多覆盖k次,问最多得到权值多少 思路:典型的区间k覆盖问题,区间连边容量1,代价-w,然后其他点相邻两两连边,容量k,代价0,跑一下费用流即可 代码: #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm&g

POJ 2135 Farm Tour(费用流)

POJ 2135 Farm Tour 题目链接 题意:给定一个无向图,边有权值,求从1到n再从n到1的最短路 思路:费用流,连边容量为1(注意是无向图),然后源点和1连容量2,n和汇点连容量是2 代码: #include <cstdio> #include <cstring> #include <vector> #include <queue> #include <algorithm> using namespace std; const int

poj 3680 Intervals 最大费用流

题意: 给n给开区间(ai,bi)及相应权值wi,现在要选一些区间,要求任一点不能被超过k个区间覆盖,目标是最大化总的权重. 分析: 转化为求最大费用流,改改最小费用流的模板就好. 代码: //poj 3680 //sep9 #include <iostream> #include <vector> #include <queue> #include <algorithm> using namespace std; const int maxN=2048;

POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)

http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3256   Accepted: 855   Special Judge Description The City has a number of municipal buildings and a number of fallout shelters that were build

POJ 2516 Minimum Cost(费用流)

POJ 2516 Minimum Cost 题目链接 题意:转一篇题意吧..感觉写的很详细了,優YoU http://blog.csdn.net/lyy289065406/article/details/6742534 思路:一开始是把所有商家的每种物品和所有供应商所有物品连边跑费用流,结果TLE了,因为这样建出来的图,边数会非常的庞大 那么其实转化一下思路,每种物品之间是不会互相影响的,那么把每种物品求出来后,累加起来就是答案了,然后注意这题数据要读完,直接判断错没读完数据就会WA 代码: #

POJ 2175 Evacuation Plan 费用流消圈

题目大意:给出一个费用流的模型和已经流过的一些边,问是否存在比这个解更优的解. 思路:直接用原图做一次费用流求最优解会T掉.先介绍费用流消圈定理:如果当前费用流的残量网络中存在负圈,那么当前流不是最优的解. 其实很好理解,结合原图和流过流量之后的反边,若出现了负圈,那么就可以沿着这个负圈增广,而且费用更小. 不过为了解决这个题我们并不需要建立完整的网络流,只需要建立残量网络之后SPFA看是否能找到负环即可. 具体建立方法: 如果一个避难地点有值,那么T向这个避难地点连边,费用0 若当前避难地点没