POJ2195
建图,直接套用模板
求出每个人到每个房子最短的距离来构造费用(cost),因为一个房子只能容纳一个人,所以容量(cap)都为1,然后建立超级源点与所有的人相连,所有的房子与超级汇点相连就行了。显然,超级源点超级汇点的费用都是0;
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
#define mem(a,x) memset(a,x,sizeof(a))
#define INF 0x3f3f3f3f
#define N 222
#define M 111*100
typedef long long ll;
using namespace std;
struct Edge{
int from,to,cap,flow,cost;
};
struct MCMF{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[N];
int inq[N]; //是否在队列中
int d[N]; //bellman_ford;
int p[N]; //上一条弧
int a[N]; //可改进量
void init(int n){
this->n = n;
for(int i=0;i<=n;i++) G[i].clear();
edges.clear();
}
void addEdge(int from,int to,int cap,int cost){
edges.push_back((Edge){from,to,cap,0,cost});
edges.push_back((Edge){to,from,0,0,-cost});
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(int s,int t,int &flow,int &cost){
for(int i=0;i<=n;i++) d[i] = INF;
mem(inq,0);
d[s] = 0;inq[s] = 1;p[s] =0;a[s] = INF;
queue<int>Q;
Q.push(s);
while(!Q.empty()){
int u = Q.front(); Q.pop();
inq[u] = 0;
for(int i=0;i<G[u].size();i++){
Edge& e = edges[G[u][i]];
if(e.cap >e.flow && d[e.to] > d[u] + e.cost){
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u] , e.cap - e.flow);
if(!inq[e.to]){ Q.push(e.to); inq[e.to] = 1;}
}
}
}
if(d[t] == INF) return false; // s-t不连通,失败退出
flow += a[t];
cost += d[t]*a[t];
for(int u=t;u!=s;u=edges[p[u]].from){
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
}
return true;
}
//需要保证初始网络中没有负圈
int minCost(int s,int t){
int flow = 0,cost = 0;
while(BellmanFord(s,t,flow,cost));
return cost;
}
}solve;
char map[101][101];
struct node{
int x,y;
}house[N],man[N];
int main(){
int n,m;while(scanf("%d%d",&n,&m),n+m){
for(int i=0;i<n;i++)scanf("%s",map[i]);
int l = 0,r = 0;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(map[i][j] == 'H')
house[l++] = node{i,j};
else if(map[i][j] == 'm')
man[r++] = node{i,j};
}
}
int src = r + l; int des = r + l+1 ;
solve.init(r+l+1);
for(int i=0;i<r;i++){
for(int j=0;j<l;j++){
int cost = abs(man[i].x - house[j].x) + abs(man[i].y - house[j].y);
solve.addEdge(i,r+j,1,cost);
}
}
for(int i=0;i<r;i++) solve.addEdge(src,i,1,0);
for(int i=0;i<l;i++) solve.addEdge(i+r,des,1,0);
int ans = solve.minCost(src,des);
printf("%d\n",ans);
}
}
POJ2135神构图
要求一个人从位置1走到位置n,然后再走回位置1,走的路不能重复,要求路径最短。
思路:
每条路正反都要建立一次图,容量都为1,这样保证了只走一次;
建立超级源点,超级汇点,因为位置1,位置n要走两次(题意要求来回一次)。
所以超级源点的到位置1的 容量(cap)为2,cost为0(显然)
位置n到超级汇点的cap为2,cost为0;
然后直接求 超级源点到超级汇点的 最小费用最大流就行了。
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
#define mem(a,x) memset(a,x,sizeof(a))
#define INF 0x3f3f3f3f
#define N 1110
#define M 111*100
typedef long long ll;
using namespace std;
struct Edge{
int from,to,cap,flow,cost;
};
struct MCMF{
int n,m,s,t;
vector<Edge> edges;
vector<int> G[N];
int inq[N]; //是否在队列中
int d[N]; //bellman_ford;
int p[N]; //上一条弧
int a[N]; //可改进量
void init(int n){
this->n = n;
for(int i=0;i<=n;i++) G[i].clear();
edges.clear();
}
void addEdge(int from,int to,int cap,int cost){
edges.push_back((Edge){from,to,cap,0,cost});
edges.push_back((Edge){to,from,0,0,-cost});
m = edges.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}
bool BellmanFord(int s,int t,int &flow,int &cost){
for(int i=0;i<=n+1;i++) d[i] = INF;
mem(inq,0);
d[s] = 0;inq[s] = 1;p[s] =0;a[s] = INF;
queue<int>Q;
Q.push(s);
while(!Q.empty()){
int u = Q.front(); Q.pop();
inq[u] = 0;
for(int i=0;i<G[u].size();i++){
Edge& e = edges[G[u][i]];
if(e.cap >e.flow && d[e.to] > d[u] + e.cost){
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u] , e.cap - e.flow);
if(!inq[e.to]){ Q.push(e.to); inq[e.to] = 1;}
}
}
}
if(d[t] == INF) return false; // s-t不连通,失败退出
flow += a[t];
cost += d[t]*a[t];
int u = t;
while(u != s){
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
u = edges[p[u]].from;
}
return true;
}
int minCost(int s,int t){
int flow = 0,cost = 0;
while(BellmanFord(s,t,flow,cost));
return cost;
}
}solve;
int main(){
int n,m;while(scanf("%d%d",&n,&m)!=EOF){
int a,b,c;
solve.init(n);
for(int i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
solve.addEdge(a,b,1,c);
solve.addEdge(b,a,1,c);
}
solve.addEdge(0,1,2,0);
solve.addEdge(n,n+1,2,0);
int ans = solve.minCost(0,n+1);
printf("%d\n",ans);
}
}
模板还是比较可靠的 - -