POJ2195: Going Home 题解

来源:互联网 发布:大芒果数据库密码 编辑:程序博客网 时间:2024/06/08 04:43

这道题是费用流模板题

处理费用流可以用edmonds-karp+spfa算法,这样可以有效的处理负边,但spfa的复杂度不够稳定

我们可以导入势的概念从而使用dijkstra+edmonds-karp来解决费用流

设顶点i的势为h(i),我们将图中原来的边d(e)变成d'(e)=d(e)+h(u)-h(v),这样改动后的图最终的答案只要减去h(s)-h(t)就是原图的答案

所以只要合理的选取势,就可以使得所有的d'(e)都是非负数,从而可以使用djikstra()

对于h(i),可以取dist[i]作为势的值,因为在djikstra算法中有

dist[v]<=dist[u]+d(e),e是连接u和v的边

如果刚开始有负边,就先跑一趟spfa,否则可以直接跑dijkstra (注意反向边中的负边不算,因为刚开始反向边没有流量不会走到)

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <cmath>#include <algorithm>#include <cstdlib>#include <utility>#include <map>#include <stack>#include <set>#include <vector>#include <queue>#include <deque>#define x first#define y second#define mp make_pair#define pb push_back#define LL long long#define Pair pair<int,int>#define LOWBIT(x) x & (-x)using namespace std;const int MOD=1e9+7;const int INF=0x7ffffff;const int magic=348;int prevv[100048],pree[100048];int t=0,head[100048],to[200048],nxt[200048],f[200048],w[200048],tot=1;void addedge(int s,int t,int cap,int cost){to[++tot]=t;nxt[tot]=head[s];head[s]=tot;f[tot]=cap;w[tot]=cost;to[++tot]=s;nxt[tot]=head[t];head[t]=tot;f[tot]=0;w[tot]=-cost;}int n,m,cnt;char a[148][148];vector<Pair> people,house;priority_queue<Pair> q;int dist[100048],h[100048];inline int myabs(int x){return x>=0?x:-x;}inline int calc(Pair x,Pair y){int x1=x.x,y1=x.y,x2=y.x,y2=y.y;return myabs(x1-x2)+myabs(y1-y2);}bool dijkstra(){int i,x,y,dd;q.push(mp(0,0));for (i=0;i<=t;i++) dist[i]=INF;dist[0]=0;while (!q.empty()){dd=q.top().x;x=q.top().y;dd=-dd;q.pop();if (dd>dist[x]) continue;for (i=head[x];i;i=nxt[i]){y=to[i];if (f[i] && dist[y]>dist[x]+w[i]+h[x]-h[y]){dist[y]=dist[x]+w[i]+h[x]-h[y];prevv[y]=x;pree[y]=i;q.push(mp(-dist[y],y));}}}if (dist[t]>=INF) return false; else return true;}int min_cost_flow(){int i,x,y,u,res,minf;for (i=0;i<=t;i++) h[i]+=dist[i];minf=INF;for (u=t;u;u=prevv[u])minf=min(minf,f[pree[u]]);res=minf*h[t];for (u=t;u;u=prevv[u]){f[pree[u]]-=minf;f[pree[u]^1]+=minf;}return res;}int main (){int i,j;while (scanf("%d%d",&n,&m) && n && m){for (i=1;i<=n;i++) scanf("%s",a[i]+1);people.clear();house.clear();t=0;tot=1;for (i=1;i<=n;i++)for (j=1;j<=m;j++){if (a[i][j]!='.') t++;if (a[i][j]=='m') people.pb(mp(i,j));if (a[i][j]=='H') house.pb(mp(i,j));}cnt=t/2;t++;for (i=0;i<=t;i++) head[i]=0;for (i=0;i<=t;i++) h[i]=0;for (i=1;i<=cnt;i++) addedge(0,i,1,0);for (i=1;i<=cnt;i++) addedge(cnt+i,t,1,0);for (i=0;i<people.size();i++)for (j=0;j<house.size();j++){int d=calc(people[i],house[j]);addedge(i+1,cnt+j+1,1,d);}int ans=0;while (dijkstra()) ans+=min_cost_flow();printf("%d\n",ans);}return 0;}


原创粉丝点击