经销商问题(zkw费用流不适用稠密图) [新-柯黑的提醒]

【题十】经销商问题(profit.cpp/c/pas)

师大附中  柯嵩宇

时间限制:1s 内存限制 256MB

 

【问题描述】

CTY神犇成为了著名品牌的一个经销商,由于经营有方,他创造了商品销售上的奇迹——就是进多少卖多少。为了可以获得更多的利润,他决定从其他经销商那里进货。进货的要遵循以下规则:

1.有一个顶级经销商,他有无限的库存,他的出货价总是恒定的。

2.其他的经销商只能间接或直接从顶级经销商进货,而且一个经销商向其他经销商进货的量应等于向其他经销商出货的量(即假设经销商都只会把商品卖给别的经销商)(顶级经销商和CTY神犇例外)。

3.经销商之间有单向的买卖关系,一个经销商v会向u要求进货,当且仅当存在u->v的单向买卖关系,同理,u会向v出货也是要求当且仅当存在u->v的单向买卖关系。

4.代理一个产品最主要的就是获利,一个经销商向另一个经销商出货时会在进货价上加上x%在卖给购买方(例外的是顶级经销商有着固定的出货价,他的出货价不会随着进货价而变动)。由于经销商之间亲密程度不同,所以每一条单向买卖关系的加价幅度(即x%)不一定相同,而且对于一个单向买卖关系<ui, vi>而言,经销商ui最多愿意卖给vi的商品数为ci。

根据以上规则,CTY神犇想知道他最多可以拿到多少的商品,而由于售价是一定的,CTY神犇想要以尽量低的总成本购进尽量多的商品。他发现经销商的关系有点小复杂,编程解决又太水了,所以他决定把这个简单的任务交给你。

【输入格式profit.in】

第一行n,m,s表示共有n个经销商,m条单向买卖关系,顶级经销商的出货价格为s(其中顶级经销商的编号为1,CTY神犇的编号为n)

接下来m行,每行4个正整数;u, v, c,x表示经销商u和v之间存在最多销售c和加价x%的单向买卖关系。

根据题意,输入数据保证顶级经销商卖给其他经销商的价格总是恒定的,即xi=0。

数据保证没有重边。

【输出格式profit.out】

第一行一个数sum,表示最多的进货量。

第二行一个数cost,表示获得最多进货量的最小成本。

进货成本精确到一位小数。

无法进货时输出:

0

0.0

【输入样例】

3 3 5

1 2 4 0

2 3 3 100

1 3 3 0

【输出样例】

6

45.0

【数据范围】

对于40%的数据n<=500

对于100%的数据n<=1800,m<=n * (n - 1) / 2,0<=x<=100

 

这题大家应该都会……(建图)

然后注意totcost+=pow(2,d[1])*flow (pow必须每次都求)

问题来了……这是zkw费用流写的:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<functional>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,n) for(int i=k;i<=n;i++)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define MAXN (1800+10)
#define INF (1000000000)
#define MAXM (MAXN*(MAXN-1))
#define eps 1e-9
double cost[MAXM];
int pre[MAXN]={0},edge[MAXM],next[MAXM]={0},weight[MAXM],size=1;
void addedge(int u,int v,int w,double c)
{
	edge[++size]=v;
	weight[size]=w;
	cost[size]=c;
	next[size]=pre[u];
	pre[u]=size;
}
void addedge2(int u,int v,int w,double c){addedge(u,v,w,c),addedge(v,u,0,-c);}
double x1,totcost=0;
int n,m;
double slock[MAXN],d[MAXN];
bool b[MAXN];
bool model()
{
	double delta=1e9;
	For(i,n) if (!b[i]) delta=min(slock[i],delta),slock[i]=INF;
	if (abs(delta-1e9)<eps) return 0;
	For(i,n) if (b[i]) d[i]+=delta;
	return 1; 
}
int dfs(int x,int flow)
{
	b[x]=1;//cout<<x<<' ';
	if (x==n) {totcost+=pow(2,d[1])*flow;return flow;}
	int nowflow=0;
	Forp(x)
	{
		int &v=edge[p];
		if (weight[p])
		{
			if (abs(d[x]-d[v]-cost[p])<eps) 
			{
				int fl=cost[p]<eps&&b[v]?0:dfs(v,min(flow,weight[p]));
				if (fl) {weight[p]-=fl;weight[p^1]+=fl;nowflow+=fl;flow-=fl;}
				if (!flow) return nowflow;				
			}
			else slock[v]=min(slock[v],d[v]+cost[p]-d[x]);
		}
	}
	return nowflow;	
}
int sap()
{
	int nowflow=0,flow=0;
	For(i,n) slock[i]=INF;
	do
	{
		do
		{
			memset(b,0,sizeof(b));
			nowflow=dfs(1,INF);
			flow+=nowflow;
		}while (nowflow);
	}while (model());
	return flow;
}
int main()
{
	freopen("profit.in","r",stdin);
	freopen("profit.out","w",stdout);
	scanf("%d%d%lf",&n,&m,&x1);
	int u,v,w;
	double x;
	For(i,m)
	{
		scanf("%d%d%d%lf",&u,&v,&w,&x);
		if (u==1) x=(double)x1;
		else x=(double)(x/100+1);
		x=log2(x);
		addedge2(u,v,w,x);
	}
	int sum=sap();
	printf("%d\n%.1lf\n",sum,totcost);
	return 0;
}
上面这个程序会T


果然稠密图中dfs的增广要比bfs慢很多


结论:千万别图省事跑zkw。


2013.5.9

今天柯黑说搜到了这个Blog(可是连我自己都没成功搜过……),果然查学术相关还是要去Google

言归正传,ksy说我这个是很旧的zkw(T_T)

其实重标号明显要用SPFA+SLF+LLF……我的2个O(n)For居然还不如SPFA》(T_T+1)

zkw费用流的精髓其实是dfs代替bfs

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<functional>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,n) for(int i=k;i<=n;i++)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define MAXN (1800+10)
#define INF (1000000000)
#define MAXM (MAXN*(MAXN-1))
#define eps 1e-9
double cost[MAXM];
int pre[MAXN]={0},edge[MAXM],next[MAXM]={0},weight[MAXM],size=1;
void addedge(int u,int v,int w,double c)
{
	edge[++size]=v;
	weight[size]=w;
	cost[size]=c;
	next[size]=pre[u];
	pre[u]=size;
}
void addedge2(int u,int v,int w,double c){addedge(u,v,w,c),addedge(v,u,0,-c);}
double x1,totcost=0;
int n,m;
double slock[MAXN],d[MAXN];
bool b[MAXN];
int q[MAXN*8];
bool model()
{
/*
	double delta=1e9;
	For(i,n) if (!b[i]) delta=min(slock[i],delta),slock[i]=INF;
	if (abs(delta-1e9)<eps) return 0;
	For(i,n) if (b[i]) d[i]+=delta;
	return 1; */
	For(i,n) d[i]=INF;
	d[n]=0;q[1]=n;
	int head=1,tail=1;
	while (head<=tail)
	{
		int x=q[head];
		Forp(x)
		{
			int &v=edge[p];
			if (weight[p^1]>0&&d[x]+cost[p^1]+eps<d[v])
			{
				d[v]=d[x]+cost[p^1];
				if (head&&d[q[head]]>d[v]) q[head--]=v;
				else q[++tail]=v;
			}
		}
		head++;
	}
	if (d[1]!=INF) return 1;return 0;
}
int dfs(int x,int flow)
{
	b[x]=1;//cout<<x<<' ';
	if (x==n) return flow;
	int nowflow=0;
	Forp(x)
	{
		int &v=edge[p];
		if (weight[p])
		{
			if (abs(d[x]-d[v]-cost[p])<eps) 
			{
				int fl=cost[p]<eps&&b[v]?0:dfs(v,min(flow,weight[p]));
				if (fl) {weight[p]-=fl;weight[p^1]+=fl;nowflow+=fl;flow-=fl;}
				if (!flow) return nowflow;				
			}
			else slock[v]=min(slock[v],d[v]+cost[p]-d[x]);
		}
	}
	return nowflow;	
}
int sap()
{
	int nowflow=0,flow=0;
	For(i,n) slock[i]=INF;
	do
	{
		do
		{
			memset(b,0,sizeof(b));
			nowflow=dfs(1,INF);
			flow+=nowflow;
			totcost+=exp(d[1])*nowflow;
		}while (nowflow);
	}while (model());
	return flow;
}
int main()
{
	freopen("profit.in","r",stdin);
	freopen("profit.out","w",stdout);
	scanf("%d%d%lf",&n,&m,&x1);
	int u,v,w;
	double x;
	For(i,m)
	{
		scanf("%d%d%d%lf",&u,&v,&w,&x);
		if (u==1) x=(double)x1;
		else x=(double)(x/100+1);
		x=log(x);
		addedge2(u,v,w,x);
	}
	int sum=sap();
	printf("%d\n%.1lf\n",sum,totcost);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值