【POJ 2195】 Going Home(最小费)
最小费用最大流问题,以前一直以为这个跟最小费不是一个问题(当时不造最小费怎么玩,现在想想还是太naive。。。)
题目中说最多100个房子 人和房子的数量又一样,这样加上一个超级源点跟超级汇点 总共是0 [1,maxman] [maxman,maxman+maxhouse] maxman+maxhouse+1
然后让超级源点到每个人流量1 消费0 每个人到每个房子流量1 消费为距离 房子到汇点流量1 消费0
然后就不断搜 一直搜到不能再增广即可
代码如下:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <queue> using namespace std; const int INF = 0x3f3f3f3f; struct Point { int x,y; Point(){} Point(int _x,int _y):x(_x),y(_y){} int operator ^ (const struct Point a) { return abs(x-a.x)+abs(y-a.y); } }; struct Edge { int v,cost,cup; int next; Edge(){} Edge(int _v,int _cost,int _cup,int _next):v(_v),cost(_cost),cup(_cup),next(_next){} }; //邻接表建图 int head[233]; Edge eg[40808]; int tp; //存人跟房子的坐标 Point house[102],man[102]; int tph,tpm; //搜最小费 更新流量 int dis[233],pre[233]; bool vis[233]; int n,m,st,en,cost; void init() { memset(head,-1,sizeof(head)); tph = tpm = 0; tp = 0; } void Add(int u,int v,int cost,int cup) { //printf("%d->%d %d %d\n",u,v,cost,cup); eg[tp] = Edge(v,cost,cup,head[u]); head[u] = tp++; eg[tp] = Edge(u,-cost,0,head[v]); head[v] = tp++; } bool spfa() { int minflow = INF; memset(dis,INF,sizeof(dis)); memset(vis,0,sizeof(vis)); pre[en] = -1; queue <int> q; q.push(st); vis[st] = 1; pre[st] = -1; dis[st] = 0; while(!q.empty()) { int u = q.front(); vis[u] = 0; q.pop(); for(int i = head[u]; i != -1; i = eg[i].next) { int v = eg[i].v; //printf("%d %d\n",u,v); if(dis[v] > dis[u]+eg[i].cost && eg[i].cup) { dis[v] = dis[u]+eg[i].cost; minflow = min(minflow,eg[i].cup); pre[v] = i; if(!vis[v]) { q.push(v); vis[v] = 1; } } } } if(pre[en] == -1) return 0; cost += dis[en]; for(int i = pre[en]; i != -1;i = pre[eg[i^1].v]) { eg[i].cup -= minflow; eg[i^1].cup += minflow; } return 1; } int main() { char str[233]; while(scanf("%d %d",&n,&m) && (n+m)) { init(); for(int i = 1; i <= n; ++i) { scanf("%s",str+1); for(int j = 1; j <= m; ++j) { if(str[j] == 'm') { man[++tpm] = Point(i,j); } else if(str[j] == 'H') { house[++tph] = Point(i,j); } } } st = 0, en = tpm*2+1; for(int i = 1; i <= tpm; ++i) Add(st,i,0,1); for(int i = tpm+1; i <= tpm*2; ++i) Add(i,en,0,1); for(int i = 1; i <= tpm; ++i) for(int j = 1; j <= tph; ++j) Add(i,tpm+j,man[i]^house[j],1); cost = 0; while(spfa()); printf("%d\n",cost); } return 0; }