【bzoj4898】[Apio2017]商旅 Floyd+分数规划+Spfa

题目描述

有n个点、m条边、和k种商品。第$i$个点可以以$B_{ij}$的价格买入商品$j$,并以$S_{ij}$的价格卖出。任何时候只能持有一个商品。求一个环,使得初始不携带商品时以某种交易方式走过一圈所得的利润/路径长度(向下取整)最大。

输入

第一行包含3个正整数N,M和K,分别表示集市数量、道路数量和商品种类数量。

接下来的N行,第行中包含2K个整数描述一个集市Bi,1 Si,1 Bi,2 Si,2...Bik Si,k。

对于任意的1<=j<=k,整数和分别表示在编号为的集市上购买、卖出编号为的商品时的交易价格。

如果一个交易价格为-1,则表示这个商品在这个集市上不能进行这种交易。

接下来M行,第行包含3个整数Vp,Wp和Tp,表示存在一条从编号为Vp的市场出发前往编号为Wp的市场的路径花费Tp分钟。

1<=N<=100,1<=M<=9900

如果在编号为的集市i中,编号为j的商品既可以购买又可以卖出则0<Si,j<=Bi,j<=10^9

对于编号为P(1<=P<=M)的道路,保证Vp<>Wp且1<=Tp<=10^7

不存在满足1<=P<Q<=M的P,Q,使得(Vp,Wp)=(Vq,Wq) 。

输出

输出包含一个整数,表示盈利效率最高的环路盈利效率,答案向下取整保留到整数。如果没有任何一条环路可以盈利,则输出0。

样例输入

4 5 2
10 9 5 2
6 4 20 15
9 7 10 9
-1 -1 16 11
1 2 3
2 3 3
1 4 1
4 3 1
3 1 1

样例输出

2



题解

Floyd+分数规划+Spfa

题目显然是一个分数规划的模型,但是如果直接使用分层图模拟商品买卖的过程的话肯定会TLE。

我们不妨换个思路:考虑每件两点之间的连续交易。即在A地购买商品,并在B地卖出的这个过程。

那么这个过程走的一定是最短路,买卖的一定是盈利最大的商品(当无法盈利时显然不进行买卖,盈利为0)。

所以可以使用Floyd求出任意两点之间最短路,再处理出来任意两点之间的最大盈利。

然后就可以对这个图求最大比率环了。二分答案,把每条边的权值看作 最大盈利-最短路*mid ,如果有非负环则说明mid成立,否则mid不成立。

时间复杂度$O(n^2k+n^3\log v)$。

#include <queue>
#include <cstdio>
#include <cstring>
#define N 110
#define K 1010
using namespace std;
typedef long long ll;
queue<int> q;
int n , len[N][N] , val[N][N] , b[N][K] , s[N][K] , inq[N] , num[N];
ll dis[N];
inline bool judge(int mid)
{
	int x , i;
	while(!q.empty()) q.pop();
	for(i = 1 ; i <= n ; i ++ ) dis[i] = inq[i] = num[i] = 0 , q.push(i);
	while(!q.empty())
	{
		x = q.front() , q.pop() , inq[x] = 0;;
		for(i = 1 ; i <= n ; i ++ )
		{
			if(dis[i] <= dis[x] + val[x][i] - (ll)mid * len[x][i])
			{
				dis[i] = dis[x] + val[x][i] - (ll)mid * len[x][i];
				if(!inq[i])
				{
					if(num[i] == n) return 1;
					num[i] ++ , inq[i] = 1 , q.push(i);
				}
			}
		}
	}
	return 0;
}
int main()
{
	int m , p , i , j , k , x , y , z , l = 1 , r = 0 , mid , ans = 0;
	scanf("%d%d%d" , &n , &m , &p);
	for(i = 1 ; i <= n ; i ++ )
		for(j = 1 ; j <= p ; j ++ )
			scanf("%d%d" , &b[i][j] , &s[i][j]);
	for(i = 1 ; i <= n ; i ++ )
		for(j = 1 ; j <= n ; j ++ )
			for(k = 1 ; k <= p ; k ++ )
				if(~b[i][k] && ~s[j][k])
					val[i][j] = max(val[i][j] , s[j][k] - b[i][k]);
	memset(len , 0x3f , sizeof(len));
	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , len[x][y] = z , r = max(r , z);
	for(k = 1 ; k <= n ; k ++ )
		for(i = 1 ; i <= n ; i ++ )
			for(j = 1 ; j <= n ; j ++ )
				len[i][j] = min(len[i][j] , len[i][k] + len[k][j]);
	while(l <= r)
	{
		mid = (l + r) >> 1;
		if(judge(mid)) ans = mid , l = mid + 1;
		else r = mid - 1;
	}
	printf("%d\n" , ans);
	return 0;
}
时间: 2024-08-27 22:23:31

【bzoj4898】[Apio2017]商旅 Floyd+分数规划+Spfa的相关文章

luogu3778/bzoj4898 商旅 (floyd+分数规划+spfa)

首先floyd求出来每两点间的最短距离,然后再求出来从某点买再到某点卖的最大收益 问题就变成了找到一个和的比值最大的环 所以做分数规划,二分出来那个答案r,把边权变成w[i]-r*l[i],再做spfa判正环就行了 (本来想偷懒用floyd判正环,结果T了) 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define CLR(a,x) memset(a,x,sizeof(a)) 4 using namespace s

【bzoj1690】[Usaco2007 Dec]奶牛的旅行 分数规划+Spfa

题目描述 作为对奶牛们辛勤工作的回报,Farmer John决定带她们去附近的大城市玩一天.旅行的前夜,奶牛们在兴奋地讨论如何最好地享受这难得的闲暇. 很幸运地,奶牛们找到了一张详细的城市地图,上面标注了城市中所有L(2 <= L <= 1000)座标志性建筑物(建筑物按1..L顺次编号),以及连接这些建筑物的P(2 <= P <= 5000)条道路.按照计划,那天早上Farmer John会开车将奶牛们送到某个她们指定的建筑物旁边,等奶牛们完成她们的整个旅行并回到出发点后,将她们

【bzoj1486】[HNOI2009]最小圈 分数规划+Spfa

题目描述 样例输入 4 5 1 2 5 2 3 5 3 1 5 2 4 3 4 1 3 样例输出 3.66666667 题解 分数规划+Spfa判负环 二分答案mid,并将所有边权减去mid,然后再判负环,若有负环则调整下界,否则调整上界,直至上下界基本重合. 证明:显然 由于有(c+d)/(a+b+k)>(c+d)/(a+b)≥min(c/a,d/b),所以两个相交环形成的新环一定不是最优解,即答案一定是简单环. 如果存在环使得边权和/点数<mid,那么就有边权和<点数*mid. 又因

POJ 3621 Sightseeing Cows 【01分数规划+spfa判正环】

题目链接:http://poj.org/problem?id=3621 Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11526   Accepted: 3930 Description Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big ci

bzoj1690:[Usaco2007 Dec]奶牛的旅行(分数规划+spfa判负环)

前段时间准备省选没更,后段(?)时间省选考砸没心情更,最近终于开始恢复刷题了... 题目大意:有n个点m条有向边的图,边上有花费,点上有收益,点可以多次经过,但是收益不叠加,边也可以多次经过,但是费用叠加.求一个环使得收益和/花费和最大,输出这个比值. 显然这就是经典的分数规划题啊,就是最优比率环,那么就二分答案,将所有边(u,v)的边权改为[v的点权-(u,v)原边权*mid],这可以算是最优比率环的公式了吧,然后判一下是否有正环,有的话就说明答案可行.判正环有够别扭的,那就全部改成相反数然后

bzoj 1690: [Usaco2007 Dec]奶牛的旅行——分数规划+spfa判负环

Description 作为对奶牛们辛勤工作的回报,Farmer John决定带她们去附近的大城市玩一天.旅行的前夜,奶牛们在兴奋地讨论如何最好地享受这难得的闲暇. 很幸运地,奶牛们找到了一张详细的城市地图,上面标注了城市中所有L(2 <= L <= 1000)座标志性建筑物(建筑物按1..L顺次编号),以及连接这些建筑物的P(2 <= P <= 5000)条道路. 按照计划,那天早上Farmer John会开车将奶牛们送到某个她们指定的建筑物旁边,等奶牛们完成她们的整个旅行并回到

01分数规划+spfa判负环 POJ3621 Sightseeing Cows

Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 10348   Accepted: 3539 Description Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big city! The cows must decide how best to

[Usaco2007 Dec][BZOJ1690] 奶牛的旅行|分数规划|二分|SPFA

1690: [Usaco2007 Dec]奶牛的旅行 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 700  Solved: 363[Submit][Status][Discuss] Description 作为对奶牛们辛勤工作的回报,Farmer John决定带她们去附近的大城市玩一天.旅行的前夜,奶牛们在兴奋地讨论如何最好地享受这难得的闲暇. 很幸运地,奶牛们找到了一张详细的城市地图,上面标注了城市中所有L(2 <= L <= 1000)座标志

bzoj1690:[Usaco2007 Dec]奶牛的旅行 (分数规划 &amp;&amp; 二分 &amp;&amp; spfa)

用dfs优化的spfa判环很快啦 分数规划的题目啦 二分寻找最优值,用spfa判断能不能使 Σ(mid * t - p) > 0 最优的情况只能有一个环 因为如果有两个环,两个环都可以作为奶牛的行程,如果两个环单独计算的结果不一样,那么两个环中比值更大的才是最优解,如果结果一样,多算一个环就没有意义了. 代码如下 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespa