洛谷P3381【模板】最小费用最大流

题目链接:

https://www.luogu.org/problem/show?pid=3381

题目大意:

求最大流和费用流

题目思路:

最小费用最大流模板题,注意事项都在模板中标注。

代码:

#include   
  
using namespace std;  
int n,m;  
int S,T;  //S是源点 T是汇点 
const int MAXN = 5010;  //点的最大值
const int MAXM = 100100;  //边的最大值
const int INF = 0x7fffffff;  //inf开错 可能会t 

struct Edge{  
    int to,next,cap,flow;  
    int cost;  
} edge[MAXM];  

int head[MAXN],tol;  
int pre[MAXN];  
int dis[MAXN];  
bool vis[MAXN];  
int N;  
void init()  //不要忘了init() 
{  
    N = n+10;   //不要开的过大 可能会T 
    tol = 0;  
    memset(head,-1,sizeof(head));
	//S=0;//源点 超级源点可以自己设置 
	//T=n+1;  //汇点 ,我在这里开n+10结果超时了,不明觉厉 超级汇点可以自己设置 
}  

void addedge(int u,int v,int cap,double cost)  //建边,cap是容量cost是费用 
{  
    edge[tol].to = v;  
    edge[tol].cap = cap;  
    edge[tol].cost = cost;  
    edge[tol].flow = 0;  
    edge[tol].next = head[u];  
    head[u] = tol++;  
    edge[tol].to = u;  
    edge[tol].cap = 0;  
    edge[tol].cost = -cost;  
    edge[tol].flow = 0;  
    edge[tol].next = head[v];  
    head[v] = tol++;  
}  

bool spfa(int s,int t)  //s是源点 t是汇点 
{  
    queueq;  
    for(int i = 0; i < N; i++)  
    {  
        dis[i] = INF;  
        vis[i] = false;  
        pre[i] = -1;  
    }  
    dis[s] = 0;  
    vis[s] = true;  
    q.push(s);  
    while(!q.empty())  
    {  
  
        int u = q.front();  
        q.pop();  
        vis[u] = false;  
        for(int i = head[u]; i != -1; i = edge[i].next)  
        {  
            int v = edge[i].to;  
            if(edge[i].cap > edge[i].flow &&  
                  dis[v] - dis[u] - edge[i].cost>0 ){  //浮点数加精度判断,否则会T 
                dis[v] = dis[u] + edge[i].cost;  
                pre[v] = i;  
                if(!vis[v]){  
                    vis[v] = true;  
                    q.push(v);  
                }  
            }  
        }  
    }  
    if(pre[t] == -1)return false;  
    else return true;  
}  

int minCostMaxflow(int s,int t,int &cost){  //cost返回的是最小费用 
    int flow = 0; //这里的flow返回的是最大流 
    cost = 0;  
    while(spfa(s,t)){  
        int Min = INF;  
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]){  
            if(Min > edge[i].cap - edge[i].flow)  
                    Min = edge[i].cap - edge[i].flow;  
        }  
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]){  
            edge[i].flow += Min;  
            edge[i^1].flow -= Min;  
            cost += edge[i].cost * Min;  
        }  
        flow += Min;  
    }  
    return flow;  //求出来最大流 
}  
   
  
  
int main(){  
    scanf("%d%d%d%d",&n,&m,&S,&T);
    init();//不要忘了 init 
    for(int i=1;i<=m;i++){
    	int ui,vi,wi,fi;
    	scanf("%d%d%d%d",&ui,&vi,&wi,&fi);//求最大费的时候,******************只需要将费用取相反数即可 ********************* 
    	addedge(ui,vi,wi,fi);
	} 
	int ans=0;//ans求的是最小费用 
	printf("%d ",minCostMaxflow(S,T,ans));
	printf("%d\n",ans);
    return 0;  
}  




你可能感兴趣的:(数据结构--网络流)