zoukankan      html  css  js  c++  java
  • 晨跑【费用流】

    题目大意:

    一个有向图,每条边有流量和费用,求在每个点只经过一次的情况下(SSTT除外)的最小费用最大流。


    思路:

    原题也很容易看出是费用流。难点在于如何保证每个点只经过一次。
    那么不妨将除S,TS,T之外的点进行拆点。每个点可以拆成入点和出点,流量为1,费用为0。这样就可以保证每个点之间的边只能走一次,就达成了每个点只能经过一次的效果。
    最终的建模如下:
    这里写图片描述


    代码:

    #include <cstdio>
    #include <iostream>
    #include <queue>
    #include <cstring>
    #define Inf 1e9
    using namespace std;
    
    int n,m,k,s,t,head[80001],dist[501],p[80001],x,y,z,minn,maxflow,cost;
    bool vis[501];
    
    struct edge
    {
    	int next,c,to,w,from;
    }e[80001];
    
    void add(int from,int to,int c,int w)
    {
    	k++;
    	e[k].from=from;  //来的点
    	e[k].to=to;
    	e[k].c=c;
    	e[k].w=w;
    	e[k].next=head[from];
    	head[from]=k;
    }
    
    bool spfa()
    {
    	for (int i=0;i<=2*n+3;i++)
    	{
    		dist[i]=Inf;  //最短路
    		vis[i]=0; 
    	}
    	queue<int> q;
    	q.push(s);
    	dist[s]=0;
    	vis[s]=1;
    	while (q.size())
    	{
    		int u=q.front();
    		q.pop();
    		vis[u]=0;
    		for (int i=head[u];~i;i=e[i].next)
    		{
    			if (!e[i].c) continue;  //没流量了
    			int v=e[i].to;
    			if (dist[v]>dist[u]+e[i].w)
    			{
    				p[v]=i;
    				dist[v]=dist[u]+e[i].w;
    				if (!vis[v])
    				{
    					q.push(v);
    					vis[v]=1;
    				}
    			}
    		}
    	}
    	return (dist[t]<Inf);
    }
    
    void addflow()
    {
    	minn=Inf+1;
    	for (int i=t;p[i];i=e[p[i]].from)
    	 minn=min(minn,e[p[i]].c);  //最小流量
    	for (int i=t;p[i];i=e[p[i]].from)
    	{
    		e[p[i]].c-=minn;  //正向边
    		e[p[i]^1].c+=minn;  //反向变
    	}
    	maxflow+=minn;
    	cost+=dist[t]*minn;
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d%d",&n,&m);
    	k=1;
    	s=n*2+1;
    	t=n*2+2;
    	add(s,n+1,Inf,0);
    	add(n+1,s,0,0);
    	add(n,t,Inf,0);
    	add(t,n,0,0);
    	for (int i=1;i<=m;i++)
    	{
    		scanf("%d%d%d",&x,&y,&z); 
    		add(x+n,y,1,z);
    		add(y,x+n,0,-z);
    	}
    	for (int i=2;i<n;i++)
    	{
    		add(i,i+n,1,0);
    		add(i+n,i,0,0);
    	}
    	while (spfa())
    	 addflow();
    	printf("%d %d\n",maxflow,cost);
    	return 0;
    }
    
  • 相关阅读:
    双缓冲绘图模式
    java异常
    15-11-24 system同步与异步
    15-11-23:system指令
    使用Swing组件编写一个支持中文文本编辑程序ChineseTextEdit.java
    JTextArea 加入滚动条
    键盘事件
    monitoring_db
    del_archivelog
    Redis 4.0.14 单实例安装
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998791.html
Copyright © 2011-2022 走看看