zoukankan      html  css  js  c++  java
  • [网络流24题]运输问题

    题目:洛谷P4015、codevs1914。

    题目大意:有n个仓库和m个商店,每个仓库存有不同的货物,每个商店需要不同的货物。

    现在商店与仓库之间都有通道,可以供应的货物数量不限。

    但每个仓库运往每个商店1个货物的费用不同。

    现在问你最小的费用使得每个商店都能满足需求。

    供货量等于收货量,且数据保证正确。

    解题思路:最小费用最大流。

    首先建出二分图,然后建立超源和超汇,则此题就变为最小费用最大流的裸题了。

    第一问,求费用即可。

    第二问,把边的费用取相反数,然后费用流过程一个字节不用改,再跑一边,最后费用取相反数即可。

    C++ Code:

    #include<cstdio>
    #include<cstring>
    #include<queue>
    #define inf 0x3f3f3f3f
    std::queue<int>q;
    int n,m,cnt=-1,pre_e[255],head[255],d[255],a[255];
    bool vis[255];
    struct edge{
    	int from,to,cap,dis,nxt;
    }e[300005],ee[300005];
    inline int addedge(int u,int v,int cap,int dis){
    	e[++cnt]=(edge){u,v,cap,dis,head[u]};
    	ee[cnt]=(edge){u,v,cap,-dis,head[u]};
    	head[u]=cnt;
    	e[++cnt]=(edge){v,u,0,-dis,head[v]};
    	ee[cnt]=(edge){v,u,0,dis,head[v]};
    	head[v]=cnt;
    }
    bool maxflow(int s,int t,int& flow,int& cost){
    	memset(d,0x3f,sizeof d);
    	memset(a,0x3f,sizeof a);
    	memset(vis,0,sizeof vis);
    	memset(pre_e,0,sizeof pre_e);
    	d[s]=0;
    	vis[s]=1;
    	q.push(s);
    	while(!q.empty()){
    		int u=q.front();
    		q.pop();
    		vis[u]=false;
    		for(int i=head[u];i!=-1;i=e[i].nxt)
    		if(e[i].cap&&d[e[i].to]>d[u]+e[i].dis){
    			d[e[i].to]=d[u]+e[i].dis;
    			a[e[i].to]=(a[u]>e[i].cap)?e[i].cap:a[u];
    			pre_e[e[i].to]=i;
    			if(!vis[e[i].to]){
    				vis[e[i].to]=true;
    				q.push(e[i].to);
    			}
    		}
    	}
    	if(d[t]==inf)return 0;
    	flow+=a[t];
    	cost+=a[t]*d[t];
    	for(int i=t;i!=s;i=e[pre_e[i]].from){
    		e[pre_e[i]].cap-=a[t];
    		e[pre_e[i]^1].cap+=a[t];
    	}
    	return 1;
    }
    int mincost(int s,int t){
    	int flow=0,cost=0;
    	while(maxflow(s,t,flow,cost));
    	return cost;
    }
    int main(){
    	memset(head,-1,sizeof head);
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i){
    		int x;
    		scanf("%d",&x);
    		addedge(0,i,x,0);
    	}
    	for(int i=1;i<=m;++i){
    		int x;
    		scanf("%d",&x);
    		addedge(i+n,n+m+1,x,0);
    	}
    	for(int i=1;i<=n;++i)
    	for(int j=1;j<=m;++j){
    		int x;
    		scanf("%d",&x);
    		addedge(i,j+n,inf,x);
    	}
    	printf("%d
    ",mincost(0,n+m+1));
    	memcpy(e,ee,sizeof e);
    	printf("%d
    ",-mincost(0,n+m+1));
    	return 0;
    } 
    
  • 相关阅读:
    在 mac iTerm2 中使用 cmd 终端
    在 jupyter 中添加菜单和自动完成功能
    Bash 和 Zsh 开启 vi-mode
    免密登录和远程执行命令
    图片的筛选
    win10 右键菜单很慢的解决方式
    ssh中的 Connection closed by ***
    NodeJS 获取网页源代码
    在 JSDOM v11 中使用jQuery
    kafaka学习
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8330990.html
Copyright © 2011-2022 走看看