题目描述

有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;
}

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

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

    首先floyd求出来每两点间的最短距离,然后再求出来从某点买再到某点卖的最大收益 问题就变成了找到一个和的比值最大的环 所以做分数规划,二分出来那个答案r,把边权变成w[i]-r*l[i],再做spf ...

  2. 洛谷P3778 [APIO2017]商旅——01分数规划

    题目:https://www.luogu.org/problemnew/show/P3778 转化有点技巧: 其实直接关注比率的上下两项,也就是盈利和时间: 通过暴枚和 floyd 可以处理出两两点间 ...

  3. [APIO2017]商旅(floyd+分数规划+SPFA)

    题解:首先肯定要跑最短路,而n<=100,所以可以用floyd,然后根据比值,很容易想到二分答案,然后再SPFA跑一遍负环,就能求出解了. #include<bits/stdc++.h&g ...

  4. BZOJ4898/5367 Apio2017商旅(分数规划+floyd)

    如果要在某点买入某物品并在另一点卖出,肯定是走其间最短路径.于是预处理任意两点间的收益和最短路径,连完边二分答案判负环即可,可以全程floyd.注意inf大小. #include<iostrea ...

  5. 2018.09.09 poj2949Word Rings(01分数规划+spfa判环)

    传送门 这题要先巧妙的转化一下. 对于每个字符串,我们把头尾的两个小字符串对应的点连边,边权是这个字符串的长度. 这样最多会出现26*26个点. 这个时候就只用求出边权和跟边数的最大比值了. 这个显然 ...

  6. Bzoj1486/洛谷P3199 最小圈(0/1分数规划+spfa)/(动态规划+结论)

    题面 Bzoj 洛谷 题解(0/1分数规划+spfa) 考虑\(0/1\)分数规划,设当前枚举到的答案为\(ans\) 则我们要使(其中\(\forall b_i=1\)) \[ \frac{\sum ...

  7. [BZOJ4898] [Apio2017]商旅

    [BZOJ4898] [Apio2017]商旅 传送门 试题分析 考虑两个点之间的路径,显然如果交易的话肯定选\(S_{t,i}-B_{s,i}\)最大的. 那么我们可以先用\(Cost\)把两个点的 ...

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

    题目链接:http://poj.org/problem?id=3621 Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total ...

  9. 【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,然后再判 ...

随机推荐

  1. 字符串替换For linux C

    1.临时空间给了个1024,不需要可减少长度. 2.结果只用用strcpy了,没校验. bool Replace(char *str,const char *src, const char *des) ...

  2. OceanBase安装

    背景: OceanBase是阿里巴巴.蚂蚁金服自主研发的可扩展的分布式关系数据库,实现了数千亿条记录.数百 TB 数据上的跨行跨表事务,主要支持支付宝核心的交易.支付.会员和账务系统等 OLTP 和  ...

  3. (转)基于REST架构的Web Service设计

    原文出处:http://www.williamlong.info/archives/1728.html ------------------------------------------------ ...

  4. python__标准库 : 正则表达式(re)

    re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none. re.search 扫描整个字符串并返回第一个成功的匹配. 替换: re.sub(p ...

  5. python__基础 : 类的 __slots__ 方法

    实例在创建出来之后,可以动态的添加属性和方法, 那如果想要限制添加的实例属性,可以用一下 __slots__ 这个东西: class Test(object): __slots__ = ('name' ...

  6. C语言进阶—— 逻辑运算符分析15

    印象中的逻辑运算符: ---学生:老师,在我的印象中,逻辑运算符用在条件判断的时候,真挺简单的,还有必要深究吗? ---老师:逻辑运算符确实在条件判断的时候用的比较多,但是并不能说简单... 请思考下 ...

  7. react+redux状态管理实现排序 合并多个reducer文件

    这个demo只有一个reducer 所以合并reducer这个demo用不到 ,但是我写出来这样大家以后可以用到,很好用,管理多个reducer,因为只要用到redux就不会只有一个reducer所以 ...

  8. python sys模块和序列化模块

    sys模块是与python解释器交互的一个接口: sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0),错误退出sys.exit( ...

  9. DbVisualizer 解决中文乱码问题

    在SQL Commander中,sql语句中如果有中文,显示是‘口口口’. 解决办法如下: 在Tools->tool Properties->General->Appearance- ...

  10. 【转】Git命令解说

    3.12. Git branch  3.12.1. 总述  当第一次执行git init时,系统就会创建一个名为“master”的分支. 而其它分支则通过手工创建.  下面列举一些常见的分支策略:  ...