• poj 2516 (费用流)


    题意:有N个供应商,M个店主,K种物品。每个供应商对每种物品的的供应量已知,每个店主对每种物品的需求量的已知,从不同的供应商运送不同的货物到不同的店主手上需要不同的花费,又已知从供应商m送第k种货物的单位数量到店主n手上所需的单位花费。供应是否满足需求?如果满足,最小运费是多少?

    思路:这题一读完就知道是费用流了,刚开始想着拆点,不过算了一下,把m个供应商拆成m*k个点,n个店主拆成n*k个点,加起来有5000多个点,肯定会超时的,看了网上说每种商品求一次费用流就可以了,就是100个点求50次。





    #include<stdio.h>
    #include<queue>
    #include<string.h>
    const int inf=0x3fffffff;
    const int N=200;
    using namespace std;
    int dis[N],start,end,head[N],num,sum,pre[N],vis[N],mincost;
    int in[51][51],out[51][51],link[51][51][51];
    struct edge
    {
    	int st,ed,flow,cost,next;
    }e[N*N];
    void addedge(int x,int y,int f,int c)
    {
    	e[num].st=x;e[num].ed=y;e[num].flow=f;e[num].cost=c; e[num].next=head[x];head[x]=num++;
    	e[num].st=y;e[num].ed=x;e[num].flow=0;e[num].cost=-c;e[num].next=head[y];head[y]=num++;
    }
    bool spfa()
    {
    	queue<int>Q;
    	int i,u,v;
    	for(i=start;i<=end;i++)
    	{
    		pre[i]=-1;
    		dis[i]=inf;
    		vis[i]=0;
    	}
    	dis[start]=0;
    	vis[start]=1;
    	Q.push(start);
    	while(!Q.empty())
    	{
    		u=Q.front();
    		Q.pop();
    		vis[u]=0;
    		for(i=head[u];i!=-1;i=e[i].next)
    		{
    			v=e[i].ed;
    			if(e[i].flow<=0)continue;
    			if(dis[v]>dis[u]+e[i].cost)
    			{
    				dis[v]=dis[u]+e[i].cost;
    				pre[v]=i;
    				if(!vis[v])
    				{
    					Q.push(v);
    					vis[v]=1;
    				}
    			}
    		}
    	}
    	if(pre[end]==-1)
    		return false;
    	return true;
    }
    void Mincost()
    {
    	int i,minflow,maxflow=0;
    	mincost=0;
    	while(spfa())
    	{
    		minflow=inf;
    		for(i=pre[end];i!=-1;i=pre[e[i].st])
    			if(minflow>e[i].flow)
    				minflow=e[i].flow;
    		for(i=pre[end];i!=-1;i=pre[e[i].st])
    		{
    			e[i].flow-=minflow;
    			e[i^1].flow+=minflow;
    			mincost+=minflow*e[i].cost;
    		}
    		maxflow+=minflow;
    	}
    	if(maxflow!=sum)
    		mincost=-1;
    }
    int main()
    {
    	int i,j,n,k,m,h,sum1,cost;
    	while(scanf("%d%d%d",&n,&m,&k),n+m+k)
    	{				
    		start=0,end=n+m+1;cost=0;
    		for(i=1;i<=n;i++)		
    			for(j=1;j<=k;j++)
    			   scanf("%d",&out[i][j]);
    		for(i=1;i<=m;i++)
    		{
    			for(j=1;j<=k;j++)
    				scanf("%d",&in[i][j]);
    		}
    		for(i=1;i<=k;i++)
    		{
    			for(j=1;j<=n;j++)
    				for(h=1;h<=m;h++)
    					scanf("%d",&link[i][j][h]);
    		}
    		for(i=1;i<=k;i++)//第i种商品
    		{
    			memset(head,-1,sizeof(head));
    	        num=0;sum=0;sum1=0;
    			for(j=1;j<=n;j++)//商店需要的i种商品
    			{
    				sum+=out[j][i];
    				addedge(m+j,end,out[j][i],0);
    			}
    			for(j=1;j<=m;j++)
    			{
    				addedge(start,j,in[j][i],0);
    				sum1+=in[j][i];
    			}
    			if(sum1<sum)break;//如果i商品供不应求
    			for(j=1;j<=n;j++)
    			{
    				for(h=1;h<=m;h++)
    					addedge(h,j+m,in[h][i],link[i][j][h]);
    			}
    			Mincost();
    			if(mincost==-1)break;//第i种商品不能满足
    			cost+=mincost;
    		}
    		if(i<=k)printf("-1
    ");//有商品不能满足
    		else printf("%d
    ",cost);		
    	}
    	return 0;
    }
    


  • 相关阅读:
    导入旧版本Android项目时的“Unable to resolve target ‘android
    eclipse打开文件目录
    ireport常见问题
    【技术贴】解决127.0.0.1和http://localhost均被拦截跳转到另一个网页
    【技术贴】SqlServer2008 R2 安装失败提示出现以下错误 服务 MSSQLSERVERO
    【技术贴】解决xp下Microsoft.SqlServer.Management.PSProvider.dll
    websphere性能设置和日常维护
    【技术贴】解决支付宝充值信用卡还款跳转到网上银行报错Error 404
    jQuery制作Facebook Timeline时间轴
    借助rownum中求Oracle表中前三名(三甲:状元榜眼探花)的方法(总计三种方法,以讲述rownum的使用为主)
  • 原文地址:https://www.cnblogs.com/pangblog/p/3331214.html
Copyright © 2020-2023  润新知