#include "stdio.h" //poj 2135 最小费用最大流模板
#include "string.h"
#include <queue>
using namespace std;
#define N 1005
#define INF 0x3fffffff
struct node
{
int u,v;
int w,k;
int next;
}edge[4*N*10]; //题目中边的条数是N的十倍,每一条边建四次!
int n,m,idx,ans;
int head[N],dis[N],route[N];
bool mark[N];
void init(); //初始化部分变量
void EK(int start,int end);
int SPFA(int start,int end);
void adde(int u,int v,int w,int k);
void addedge(int u,int v,int w,int k);
int main()
{
int i;
int u,v,w;
while(scanf("%d%d",&n,&m)!=-1)
{
init();
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&u,&v,&w); //对每一条边建两次,一正一反
adde(u,v,w,1);
adde(v,u,w,1);
}
int start = 0;
adde(start,1,0,2); //为起点添两条边,单位流量费用为0
int end = n+1;
adde(n,end,0,2); //为终点添两条边,单位流量费用为0
while( SPFA(start,end) )
EK(start,end);
printf("%d\n",ans);
}
return 0;
}
void init()
{
ans = 0; //结果初始化
idx = 0;
memset(head,-1,sizeof(head)); //
}
void adde(int u,int v,int w,int k) //对其中的一条再加上一条流量为0的回路
{
addedge(u,v,w,k);
addedge(v,u,-w,0);
}
void addedge(int u,int v,int w,int k) //邻接表建边
{
edge[idx].u = u;
edge[idx].v = v;
edge[idx].w = w;
edge[idx].k = k;
edge[idx].next = head[u];
head[u] = idx;
idx++;
}
int SPFA(int start,int end) //找一条存在流量的最小费用流(存在流量就行)
{
int i;
memset(mark,false,sizeof(mark)); //初始化标记数组mark[];
memset(route,-1,sizeof(route)); //ruote[]记录流量路径(存下一条边的下标)
for(i=start;i<=end;i++) dis[i] = INF;
dis[start] = 0;
queue<int> q;
q.push(start);
mark[start] = true;
int x,y;
while(!q.empty())
{
x = q.front();
for(i=head[x];i!=-1;i=edge[i].next)
{
y = edge[i].v;
if(edge[i].k && dis[y] > dis[x] + edge[i].w)
{
dis[y] = dis[x] + edge[i].w;
route[y] = i; //route[]里面存的为边的下标
if(mark[y] == false)
{
mark[y] = true;
q.push(y);
}
}
}
q.pop();
mark[x] = false; //对出队列的点的标记还原
}
if(dis[end] == INF) return 0;
return 1;
}
void EK(int start,int end)
{
int x,y;
y = route[end];
//对于一般的最小费用最大流,需遍历一遍route[],求出最小费用路线上能流过的最大流量k(此题恰好为1,故此步省略!)
while(y!=-1)
{
x = y^1; //很特别的处理;
edge[y].k--; //对流量进行处理(正减反加)
edge[x].k++;
ans += edge[y].w;
y = route[edge[y].u]; //通过route[]访问路径上的下一个节点
}
}
转载于:https://www.cnblogs.com/ruo-yu/p/4412005.html