| ||||||||||
| Online Judge | Problem Set | Authors | Online Contests | User | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest | |||||||||
Re:纪念一下第一道最小费用最大流In Reply To:纪念一下第一道最小费用最大流 Posted by:scau200930760204 at 2010-08-27 15:10:32 > 百度里有很多大牛对这道题写了博客,但代码里没解释,我花了好几天才弄懂了这算法,现写下来给各位fish作参考,可更容易明白。
> /*poj2135 */
> #include<stdio.h>
> #include<iostream>
> #include<string>
> #include<queue>
> #include<vector>
> #define M 10002
> #define inf 1<<30
> using namespace std;
> struct Edge{
> int u,v;
> int c,f;
> int next;
> }edge[4*M];
> int pre[1002],p[1002]; //pre[]的用处在构造邻接边中,p[]记录路线
> int tot,n,m;
> int dist[1002],vist[1002];//用在spfa中,分别为:记录源点0到各点的最短距离(即费用),访问标记
> void add(int u,int v,int c,int f)
> {
> Edge e = {u,v,c,f,pre[u]}; //pre[u]是记录前一条edge中:开始点为u的边的值
> edge[tot] = e;
> pre[u] = tot++; //更新pre[u]=tot ,tot++
> }
> void addedge2(int u,int v,int c,int f)
> {
> add(u ,v ,c ,f); //正向的边,
> add(v,u,-c,0); //对应的反向边,费用为-c,流量为0
> }
> bool spfa() //寻找费用最小的可增广路,spfa算法
> {
> int u,v;
> queue<int>que;
> memset(p,-1,sizeof(p));
> memset(vist,0,sizeof(vist));
> fill(&dist[0],&dist[1002],inf);//不能用 memset(dist,inf,sizeof(dist));或用for等
> vist[0]=1;dist[0]=0;
> que.push(0);
> while(!que.empty()){
> u=que.front();que.pop();vist[u]=0;//取出队头元素
> for(int i=pre[u];i!=-1;i=edge[i].next){ //与u相接的所有边
> if(edge[i].f){ //有流量
> v=edge[i].v;
> if(dist[v]>dist[u]+edge[i].c){ //调整
> dist[v]=dist[u]+edge[i].c;
> p[v]=i;//记录路线
> if(!vist[v]){que.push(v); vist[v]=1;}//入队
> }
> }
> }
> }
> return dist[n+1]!=inf;
> }
> int cost() //因这题路的流量为1,不用求流量了
> {
> int ans=0,x;
> while(spfa()){
> ans+=dist[n+1];
> x=p[n+1];
> while(x!=-1){
> edge[x].f-=1; //正边
> edge[x^1].f+=1; //反边
> x=p[edge[x].u]; //x变为连接到 edge[x].u的边
> }
> }
> return ans;
> }
> int main()
> {
> int i,a,b,c;
> scanf("%d %d",&n,&m);
> memset(pre,-1,sizeof(pre)); tot=0;
> addedge2(0,1,0,2); //增加源点0,汇点n+1,
> addedge2(n,n+1,0,2);
> for(i=0;i<m;i++){
> scanf("%d %d %d",&a,&b,&c);
> addedge2(a,b,c,1);
> addedge2(b,a,c,1);
> }
> printf("%d\n",cost());
> return 0;
> }
>
>
> /* void addedge2(int u,int v,int c,int f)
> {
> Edge e = {u,v,c,f,pre[u]};
> edge[tot]=e; //正向的边,pre[u]是记录前一条edge中:开始点为u的边的值
> pre[u]=tot++; //更新pre[u]=tot ,tot++
> Edge e = {v,u,-c,0,pre[v]};
> edge[tot]=e; //对应的反向边,费用为-c,流量为0
> pre[v]=tot++;
> } */ //这有语法错误 948K 63MS
Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator