题 目 大 意 题目大意 题目大意
给定一个有向图 , n n n 个点 , m m m 条单向边
有 K K K 种不同的商品,商品用从 1 1 1 到 K K K 的整数编号。每个集市对每种商品都有自己的定价
对于一种商品,一个集市也可能只收购而不卖出该商品或只卖出而不收购该商品。如果一个集市收购一种商品,它收购这种商品的数量是不限的,同样,一个集市如果卖出一种商品,则它卖出这种商品的数量也是不限的。
经过集市时,你可以购买或者卖出商品,一旦你购买了一个商品,你需要把它装在背包里带走。由于你的背包非常小,任何时候你最多只能持有一个商品。在购买一个商品时,你不需要考虑你是否有足够的金钱,但在卖出时,需要注意只能卖出你拥有的商品。
你需要求出所有消耗时间为正数的环路中,盈利效率最高的环路的盈利效率。答案向下取整保留到整数。如果没有任何一条环路可以盈利,则输出 0 0 0 。
- 收益 : : : 在环路中卖出商品得到的金钱减去购买商品花费的金钱
- 消耗的时间 : : : 依次通过环路上所有道路所需要花费的时间的总和。
- 盈利效率 : : : 指从环路中得到的收益除以花费的时间。需要注意的是,一条没有任何交易的环路的盈利效率为 0 0 0 。
- 注 : : : 如果一个交易价格为 − 1 -1 −1 ,则表示这个商品在这个集市上不能进行这种交易。
解 题 思 路 解题思路 解题思路
- 预处理在 u u u 点买某个东西到 v v v 点卖出的最大获益 c u , v c_{u,v} cu,v
- F l o y d ( 多 源 ) Floyd(多源) Floyd(多源) 计算出 从 u u u 点到 v v v 点的最小时间 d i s u , v dis_{u,v} disu,v
- 二分查找盈利效率
p
p
p
- 把 u , v u , v u,v 两点的距离重新定义为 D i s u , v Dis_{u,v} Disu,v = = = c u , v − d i s u , v × p c_{u,v} - dis_{u,v} \times p cu,v−disu,v×p
- S p f a Spfa Spfa 判断是否有正环
- 嗯 ? 结束了 ? 结束了!@
A C c o d e AC code ACcode
(
l
o
n
g
l
o
n
g
long\ long
long long 大法好)
快读略 ————》》进此
#include <bits/stdc++.h>
using namespace std;
#define max(a, b) a > b ? a : b
#define min(a, b) a < b ? a : b
#define int long long
const int maxn = 1e3 + 5;
int n, m, k;
int l = 1, r, ans;
int dis[maxn][maxn], vis[maxn], D[maxn], Dis[maxn][maxn], a[maxn][maxn], b[maxn][maxn], c[maxn][maxn], fu[maxn];
inline bool check(int p)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
Dis[i][j] = c[i][j] - dis[i][j] * p;
}
}
queue<int> q;
memset(fu, 0, sizeof fu);
memset(vis, 0, sizeof vis);
memset(D, 0, sizeof D);
for (int i = 1; i <= n; i++)
{
vis[i] = 1;
fu[i] = 1;
q.push(i);
}
while (!q.empty())
{
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = 1; i <= n; i++)
{
int d = Dis[x][i];
if (dis[x][i] > INT_MAX)
continue;
if (D[x] + d >= D[i])
{
D[i] = d + D[x];
fu[i] = fu[x] + 1;
if (fu[i] > n + 10)
return true;
if (!vis[i])
{
vis[i] = 1;
q.push(i);
}
}
}
}
return false;
}
signed main()
{
memset(dis, 0x3f, sizeof dis);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
{
cin >> a[i][j] >> b[i][j];
if (a[i][j] == -1)
a[i][j] = INT_MAX;
if (b[i][j] == -1)
b[i][j] = 0;
}
}
for (int x = 1; x <= k; x++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
c[i][j] = max(c[i][j], b[j][x] - a[i][x]);
r = max(r, c[i][j]);
}
}
}
for (int i = 1, u, v, w; i <= m; i++)
{
cin >> u >> v >> w;
dis[u][v] = min(dis[u][v], w);
}
for (int k = 1; k <= n; k++)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
{
ans = max(ans, mid);
l = mid + 1;
}
else
{
r = mid - 1;
}
}
cout << ans << endl;
}