最小费用最大流模板(存边)

函数功能介绍:

Addedge(from,to,w,res) 添加一条 x->y,费用为w,残量为res的边,并一起添加其反向边,由于从0号开始,相邻两个数代表的边互为反向边(即i号边的反向边是 i^1)。

spfa.init(N)初始化点数N

spfa.find(S,T) 在 源点为S,汇点为T的图中寻找最小费用增广路,i号点的前驱边编号存在Path[i]中

代码如下(以nkoj 1589为例):

#include<cstdio> 
#include<iostream> 
#include<cstdlib> 
#include<cmath> 
#include<cstring> 
#include<queue> 
#include<vector> 
#include<algorithm> 
#define LL long long 
#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))    
using namespace std;      
      
const int inf=1e9;       
const int maxn=1000+5;       

int N,n,m,maxflow,mincost,last[maxn];   

inline void _read(int &x){       
    char ch=getchar(); bool mark=false;       
    for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;       
    for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';       
    if(mark)x=-x;       
}       

struct Edge{ 
    int from,to,res,w,Next; 
    Edge(int from,int to,int w,int res,int Next):from(from),to(to),w(w),res(res),Next(Next){} 
}; 
vector<Edge> edge; 

void Addedge(int from,int to,int w,int res){ 
    edge.push_back(Edge(from,to,w,res,last[from])); 
    last[from]=edge.size()-1; 
    edge.push_back(Edge(to,from,-w,0,last[to])); 
    last[to]=edge.size()-1; 
} 
   
int path[maxn], dist[maxn];            
bool vis[maxn];  
      
struct SPFA{       
    int  n;            
    void init(int n){ 
        this->n =n; 
        memset(last,-1,sizeof(last)); 
    }                          
    bool find(int s,int t){       
        int i;       
        CLEAR(vis);        
        for(i=1;i<=n;i++) dist[i]=inf; 
        memset(path,-1,sizeof(path)) ;      
        dist[s]=0;  path[s]=0 ;vis[s]=true;   
        queue <int> q;  q.push(s);       
        while(!q.empty()){       
            int x=q.front();       
            q.pop();vis[x]=false;  
             for(i=last[x];i!=-1;i=edge[i].Next){   
                 Edge& e=edge[i];         
                if(e.res>0&&dist[x]+e.w<dist[e.to]){       
                    dist[e.to]=dist[x]+e.w; 
                    path[e.to]=i;       
                    if(!vis[e.to]){       
                        q.push(e.to) ;       
                        vis[e.to]=true;       
                    }       
                }        
            }       
        }   
        return dist[t]<inf;         
    }       
}spfa;   

void Addflow(int s,int t){ 
    int flow=inf,i; 
    for(i=t; i!=s&&edge[path[i]].from!=0;i=edge[path[i]].from) 
        flow=min(flow,edge[path[i]].res); 
    maxflow+=flow; 
    mincost+=dist[t]; 
    for(i=t;i!=s;i=edge[path[i]].from){ 
        int x=path[i]; 
        edge[x].res-=flow; 
        edge[x^1].res+=flow; 
    } 
}   

int main(){ 
    int i,j,k,x,y,z,cnt=0; 
    N=maxflow=mincost=0; 
    _read(n); _read(m); 
    spfa.init(N=n+2);
    for(i=1;i<=m;i++){ 
        _read(x); _read(y); _read(z); 
        Addedge(x,y,z,1);  
        Addedge(y,x,z,1);
    } 
    Addedge(N-1,1,0,2); 
    Addedge(n,N,0,2); 
    while(spfa.find(N-1,N))Addflow(N-1,N); 
    cout<<mincost<<endl; 
    return 0;
}   



#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const long long inf=1000000000;
long long n,p,tk,tm,wk,wm;
long long N;
long long maxflow;
long long mincost;
long long tot_edge=0;
long long flow,cost;
long long dis[10005],path[10005];
long long a[10005];
bool flag[10005];
struct line{
	long long from,to,len,remain,fan;
};
line edge[5000005];
long long last[10005],_next[5000005];
void add_edge(long long x,long long y,long long l,long long acc){
	tot_edge++;
	edge[tot_edge].from=x;
	edge[tot_edge].to=y;
	edge[tot_edge].len=l;
	edge[tot_edge].remain=acc;
	edge[tot_edge].fan=tot_edge+1;
	_next[tot_edge]=last[x];
	last[x]=tot_edge;
	tot_edge++;
	edge[tot_edge].from=y;
	edge[tot_edge].to=x;
	edge[tot_edge].len=-l;
	edge[tot_edge].remain=0;
	edge[tot_edge].fan=tot_edge-1;
	_next[tot_edge]=last[y];
	last[y]=tot_edge;
}
bool findpath(){
	queue<long long> q;
    long long i,j,now;
    for(i=1;i<=N+2;i++){
	 	dis[i]=inf; 
		path[i]=-1;
		flag[i]=false;
	}
    dis[N+1]=path[N+1]=0;
	flag[N+1]=true; 
	q.push(N+1);
    while(q.size()){
        j=q.front();
        q.pop();
		flag[j]=false;
        for(long long h=last[j];h;h=_next[h]){
        	int v=edge[h].to;
        	if(edge[h].remain&&(dis[v]>dis[j]+edge[h].len)){
        		dis[v]=dis[j]+edge[h].len;
        		path[v]=h;
        		if(flag[v]==false){
        			flag[v]=true;
        			q.push(v);
				}
			}
		}
     }
     if(dis[N+2]<inf)return true; 
	 else return false; 
}
void addflow(){
	long long flow,cost,i;
	flow=inf;cost=0;
	i=N+2;
	while((i!=N+1)&&(path[i]!=0)){
		flow=min(flow,edge[path[i]].remain);
		cost+=edge[path[i]].len;   
		//edge[edge[path[i]].fan].len=-edge[edge[path[i]].fan].len;
		i=edge[path[i]].from;
	} 
	maxflow+=flow; 
	mincost+=flow*cost;
	i=N+2;
	while(i!=N+1){
		edge[path[i]].remain-=flow;
		edge[edge[path[i]].fan].remain+=flow;
		i=edge[path[i]].from;
	}
}
int main(){
	long long i,j,sum=0;
	cin>>n>>p>>tk>>wk>>tm>>wm;
	N=2*n;
	for(i=1;i<=n;i++)scanf("%I64d",&a[i]);
	for(i=1;i<=n;i++){
		add_edge(N+1,i,0,a[i]);
		add_edge(N+1,i+n,p,inf);
		if(i!=n)add_edge(i,i+1,0,inf);
	}
	for(i=1;i<=n;i++){
		if(i+tk<=n)add_edge(i,i+n+tk,wk,inf);
		if(i+tm<=n)add_edge(i,i+n+tm,wm,inf);
		add_edge(i+n,N+2,0,a[i]);
	}
	maxflow=0;
    mincost=0;
	while(findpath())addflow();
    printf("%I64d\n",mincost);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值