您的位置:首页 > 编程语言 > Go语言

POJ2195:Going Home(费用流入门)

2014-10-08 10:50 169 查看
http://poj.org/problem?id=2195

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <math.h>
#define inf 0x3f3f3f3f
using namespace std;
int n,m,s,t,tt;
struct pointe
{
int x,y;
} l[1001],r[1001];
struct node
{
int x,y,c,w;
int next;
} eg[20001];
char map[102][102];
int head[1001],v[1001],dis[1001],pre[1001];
void init()
{
memset(head,-1,sizeof(head));
tt=0;
s=0;
t=n*m+1;
}
void add(int xx,int yy,int cc,int ww)
{
eg[tt].x=xx;
eg[tt].y=yy;
eg[tt].c=cc;
eg[tt].w=ww;
eg[tt].next=head[xx];
head[xx]=tt++;
eg[tt].x=yy;
eg[tt].y=xx;
eg[tt].c=0;
eg[tt].w=-ww;
eg[tt].next=head[yy];
head[yy]=tt++;
}
int spfa(int s,int t)
{
for(int i=s; i<=t; i++)
{
v[i]=0;
pre[i]=-1;
dis[i]=inf;
}
queue<int>q;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int ff=q.front();
q.pop();
v[ff]=0;
//今天算是刚了解邻接边表第一次更新的是与源点相邻的第一层
//例如head[10]->1,3,5,7....;
for(int i=head[ff]; i!=-1; i=eg[i].next)
{
int w1=eg[i].y;
if(eg[i].c&&dis[w1]>dis[ff]+eg[i].w)
{
dis[w1]=dis[ff]+eg[i].w;//注意这里dis[ff]
pre[w1]=i;//算是了解么意思了
if(!v[w1])
{
v[w1]=1;
q.push(w1);
}
}
}
}
if(dis[t]==inf)
{
return 0;
}
return 1;
}
void KM(int s,int t)
{
int ans=0,minx;
while(spfa(s,t)==1)
{
minx=inf;
for(int i=pre[t]; i!=-1; i=pre[eg[i].x])
minx=min(minx,eg[i].c);
for(int i=pre[t]; i!=-1; i=pre[eg[i].x])
{
eg[i].c-=minx;
eg[i+1].c+=minx;
}
ans+=minx*dis[t];
}
cout<<ans<<endl;
return ;
}
int main()
{
int t1,t2,temp;
while(scanf("%d%d",&n,&m)!=EOF&&(n||m))
{
t1=t2=0;
init();
for(int i=1; i<=n; i++)
scanf("%*c%s",map[i]+1);
for(int i=1; i<=n; i++)
{
for(int j=1; j<=m; j++)
{
temp=(i-1)*m+j;
if(map[i][j]=='m')
{
add(s,temp,1,0);
l[t1].x=i;
l[t1++].y=j;
}
else if(map[i][j]=='H')
{
add(temp,t,1,0);
r[t2].x=i;
r[t2++].y=j;
}
}
}
for(int i=0; i<t1; i++)
{
int l1=(l[i].x-1)*m+l[i].y;
for(int j=0; j<t2; j++)
{
int l2=(r[j].x-1)*m+r[j].y;
int l3=abs(l[i].x-r[j].x)+abs(l[i].y-r[j].y);
add(l1,l2,1,l3);
}
}
KM(s,t);
}
return 0;
}


#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <queue>
#include <math.h>
#define inf 0x3f3f3f3f
using namespace std;
struct node1//记录h或者m的坐标
{
int x,y;
} a[402],b[402];
struct node
{
int x,y,c,w;
int next;
} eg[600001];
int n,m,tt,head[10001],v[10001],dis[10001],pre[10001],s,t;
char map[102][102];
void init()
{
tt=0;
memset(head,-1,sizeof(head));
s=0;
t=n*m+1;
}
void add(int xx,int yy,int cc,int ww)
{
eg[tt].x=xx;
eg[tt].y=yy;
eg[tt].c=cc;
eg[tt].w=ww;
eg[tt].next=head[xx];
head[xx]=tt++;
eg[tt].x=yy;
eg[tt].y=xx;
eg[tt].c=0;
eg[tt].w=-ww;
eg[tt].next=head[yy];
head[yy]=tt++;
}
int spfa(int s,int t)
{
queue<int>q;
for(int i=0; i<=t; i++)
{
v[i]=0;
dis[i]=inf;
pre[i]=-1;
}
v[s]=1;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int ff=q.front();
q.pop();
v[ff]=0;
for(int i=head[ff]; i!=-1; i=eg[i].next)
{
int w1=eg[i].y;
if(eg[i].c&&dis[w1]>dis[ff]+eg[i].w)
{
dis[w1]=dis[ff]+eg[i].w;
pre[w1]=i;//用边表建图存储其信息
if(!v[w1])
{
v[w1]=1;
q.push(w1);
}
}
}
}
if(dis[t]==inf)
{
return 0;
}
return 1;
}
void KM(int s,int t)
{
int min1,ans=0;
while(spfa(s,t)==1)
{
min1=inf;
for(int i=pre[t]; i!=-1; i=pre[eg[i].x])
{
if(min1>=eg[i].c)
{
min1=eg[i].c;
}
}
for(int i=pre[t]; i!=-1; i=pre[eg[i].x])
{
eg[i].c-=min1;
eg[i+1].c+=min1;
}
ans+=min1*dis[t];
}
printf("%d\n",ans);
return ;
}
int main()
{
int t1,t2;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0&&m==0) break;
init();
t1=0;
t2=0;
for(int i=1; i<=n; i++)
{
scanf("%s",map[i]+1);//因为要创建超级源点,所以从一比较好计算
for(int j=1; j<=m; j++)
{
int l=(i-1)*m+j;//以点建图
if(map[i][j]=='m')
{
add(s,l,1,0);
a[t1].x=i;
a[t1++].y=j;
}
else if(map[i][j]=='H')
{
add(l,t,1,0);
b[t2].x=i;
b[t2++].y=j;
}
}
}
for(int i=0; i<t1; i++)
{
int l1=(a[i].x-1)*m+a[i].y;//以点建图
for(int j=0; j<t2; j++)
{
int l2=abs(a[i].x-b[j].x)+abs(a[i].y-b[j].y);
int l3=(b[j].x-1)*m+b[j].y;//以点建图
add(l1,l3,1,l2);
}
}
KM(s,t);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: