zoukankan      html  css  js  c++  java
  • 「网络流24题」 17. 运输问题

    「网络流24题」 17. 运输问题

    <题目链接>


    破费用流(这四个字添加于省选后 2 个月),比较裸的板子。

    因为跑2次所以建2次图。

    数据范围邻接矩阵够用,链式前向星纯属个人习惯。

    链式前向星初始化一定记得head数组置0,不然一句e[++cnt].nxt=head[x];就给你图炸了。

    就这样。

    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    const int MAXN=210,MAXM=10210,INF=0x3f3f3f3f;
    bool exist[MAXN];
    int m,n,S,T,cnt,ans,head[MAXN],a[MAXN],b[MAXN],c[MAXM],dis[MAXN],flow[MAXN],pre[MAXN],pre_e[MAXN];
    struct edge
    {
    	int nxt,to,w,f;
    }e[MAXM];
    void AddEdge(int x,int y,int w,int f)
    {
    	e[++cnt].nxt=head[x];
    	e[cnt].to=y;
    	e[cnt].w=w;
    	e[cnt].f=f;
    	head[x]=cnt;
    }
    void AddEdges(int x,int y,int w,int f)
    {
    	AddEdge(x,y,w,f);
    	AddEdge(y,x,0,-f);
    }
    void Init(bool flag)
    {
    	cnt=ans=0;
    	memset(head,0,sizeof head);
    	for(int i=1;i<=m;++i)
    		AddEdges(S,i,a[i],0);
    	for(int i=1;i<=n;++i)
    		AddEdges(m+i,T,b[i],0);
    	for(int i=1;i<=m;++i)
    		for(int j=1,t;j<=n;++j)
    		{
    			t=c[(i-1)*n+j];
    			AddEdges(i,m+j,INF,flag ? t : -t);
    		}
    }
    bool SPFA(void)
    {
    	queue<int> q;
    	memset(exist,0,sizeof exist);
    	memset(dis,0x3f,sizeof dis);
    	memset(flow,0x3f,sizeof flow);
    	memset(pre,0,sizeof pre);
    	memset(pre_e,0,sizeof pre_e);
    	q.push(S);
    	exist[S]=1,dis[S]=0;
    	while(!q.empty())
    	{
    		int x=q.front();
    		q.pop();
    		exist[x]=0;
    		for(int i=head[x],t;i;i=e[i].nxt)
    			if(e[i].w && dis[t=e[i].to]>dis[x]+e[i].f)
    			{
    				dis[t]=dis[x]+e[i].f;
    				flow[t]=min(flow[x],e[i].w);
    				pre[t]=x,pre_e[t]=i;
    				if(!exist[t])
    				{
    					q.push(t);
    					exist[t]=1;
    				}
    			}
    	}
    	return dis[T]!=INF;
    }
    void MCMF(bool flag)
    {
    	Init(flag);
    	while(SPFA())
    	{
    		for(int i=pre[T],t;i!=S;i=pre[i])
    		{
    			e[t=pre_e[i]].w-=flow[T];
    			e[((t-1)^1)+1].w+=flow[T];
    			ans+=e[t].f*flow[T];
    		}
    	}
    	printf("%d
    ",flag ? ans : -ans);
    }
    int main(int argc,char *argv[])
    {
    	scanf("%d %d",&m,&n);
    	T=m+n+1;
    	for(int i=1;i<=m;++i)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=n;++i)
    		scanf("%d",&b[i]);
    	for(int i=1;i<=m;++i)
    		for(int j=1;j<=n;++j)
    			scanf("%d",&c[(i-1)*n+j]);
    	MCMF(1);
    	MCMF(0);
    	return 0;
    }
    

    谢谢阅读。

  • 相关阅读:
    第二次作业循环语句
    c语言01次作业分支,顺序结构
    PAT 1027. Colors in Mars
    PAT 1026 Table Tennis
    PAT 1035 Password
    PAT 1038. Recover the Smallest Number
    PAT 1028 List Sorting (25)
    PAT 1041 Be Unique (20)
    PAT 1025 PAT Ranking
    1037. Magic Coupon
  • 原文地址:https://www.cnblogs.com/Capella/p/8182717.html
Copyright © 2011-2022 走看看