poj2135(最小费用最大流)

1.思路:题目要求求出两条路径,一条正向另一条反向,并且边不走重复,因此可以转换为费用流的模型,i至j有边(无向)拆成4条边,边的容量分别至1或0

因此可以保证每条边至多走一次。再建立源s,汇t,另w(s,1)=w(n-2,t)=2;w(,1,s)=w(t,n-2)=0;c(s,1)=c(1,s)=c(n-2,t)=c(t,n-2)=0;保证每只走出两条路!

2.代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
#define N 1010
#define M 41000
#define INF 1000000000

struct Node{
    int u,v,next;
    int w,c;//cost
};
struct Graph{
    Node E[M];
    int first[N];
    int _V,_E,src,dest;
    int que[N],front,rear;
    bool vis[N];
    int cost[N],num[N],pre[N];
	
    void init(int n){
        _V=n+2,_E=0;
        src=0,dest=_V-1;
        memset(first,-1,4*_V);//!!
    }
    void build(int n,int m)
    {
        init(n);
        int u,v,w;
        for(int i=0; i<m; i++)
        {
            scanf("%d%d%d",&u,&v,&w);
            add(u,v,1,w);add(v,u,1,w);
        }
        add(src,1,2,0);add(_V-2,dest,2,0);
    }
	void add(int u,int v,int c,int w){
		E[_E].u=u,E[_E].v=v,E[_E].c=c,E[_E].w=w,E[_E].next=first[u],first[u]=_E,_E++;
		E[_E].u=v,E[_E].v=u,E[_E].c=0,E[_E].w=-w,E[_E].next=first[v],first[v]=_E,_E++;//
	}
	bool spfa(){
		for(int i=0;i<_V;i++)cost[i]=INF,vis[i]=num[i]=false;
		cost[src]=0;pre[src]=-1;
		front=rear=0;
		que[rear++]=src;
		vis[src]=true;num[src]++;
		
		while(front!=rear){
			int u=que[front++],v;
			vis[u]=false;
			if(front==N)front=0;
			for(int e=first[u];e!=-1;e=E[e].next){
				v=E[e].v;
				if(E[e].c&&cost[v]>cost[u]+E[e].w){
					cost[v]=cost[u]+E[e].w;
					pre[v]=e;
					if(!vis[v]){
						que[rear++]=v;
						if(rear==N)rear=0;
						vis[v]=true;num[v]++;
						if(num[v]>_V)return false;
					}
				}
			}
		}
		return cost[dest]<INF;
	}
	int minCostMaxFlow(){
		int minCost=0;
		while(spfa()){
			int e,aug=INF;//!!
			for(e=pre[dest];e!=-1;e=pre[E[e].u])aug=aug<E[e].c?aug:E[e].c;
			for(e=pre[dest];e!=-1;e=pre[E[e].u])E[e].c-=aug,E[e^1].c+=aug;
			minCost+=cost[dest]*aug;
		}
		return minCost;
	}
	void display(){
		for(int i=0; i<_V; i++){
			for(int e=first[i]; e!=-1; e=E[e].next){
				int u=E[e].u,v=E[e].v,c=E[e].c,w=E[e].w;
				cout<<u<<' '<<v<<' '<<c<<' '<<w<<endl;
			}
		}
	}
} net;

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("data.in", "r", stdin);
    #endif

	int n,p;
	cin>>n>>p;
	net.build(n,p);
//	net.display();
	cout<<net.minCostMaxFlow()<<endl;
	return 0;
}
//


大家把其中的

if(rear==N)rear=0;

改成

if(rear==N)front=0;

用C++提交试试会有神奇的事情发生!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值