题目链接:https://ac.nowcoder.com/acm/contest/33188/D
AC代码:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=52837882
题意:
Link正在开发一个游戏。在这个游戏中,玩家可以用 k ∗ a i k*a_i k∗ai 个 b i b_i bi 物品兑换 k ∗ c i k*c_i k∗ci 个 d i d_i di 物品。
有一天Link发现玩家可以利用这个规则刷取无穷个物品。但是Link不希望修改每个兑换的规则。
因此他引入了常数 w ,现在,玩家可以用 k ∗ a i k*a_i k∗ai 个 b i b_i bi 物品兑换 k ∗ w ∗ c i k*w*c_i k∗w∗ci 个 d i d_i di 物品。
请问在使得玩家不能刷取无穷多物品的条件下,w 的最大取值。
输入:
3 3
1 1 2 2
1 2 2 1
1 3 1 1输出:
0.5000000000
容易想到,可以把原问题转化为一个图论问题:
1:把“ k ∗ a i k*a_i k∗ai 个 b i b_i bi 物品兑换 k ∗ c i k*c_i k∗ci 个 d i d_i di 物品 ” 转化为 b i → d i b_i\rightarrow d_i bi→di 的边权为 c i a i \frac{c_i}{a_i} aici 的一条有向边。
2:原问题转化为,对于图中的每一个环 E { e 1 , e 2 , ⋯ e n } E \{e_1,e_2,\cdots e_n\} E{e1,e2,⋯en},都满足 ∏ i = 1 n ( w ∗ e i ) ⩽ 1 \prod \limits_{i=1}^n(w*e_i)\leqslant1 i=1∏n(w∗ei)⩽1
3:两边同时取log,得: ∑ i = 1 n ( log w + log e i ) ⩽ 0 \sum_{i=1}^n(\log{w}+\log{e_i})\leqslant0 ∑i=1n(logw+logei)⩽0
4:因为上述不等式满足单调性,因此可以二分查找满足条件的 w 的最大取值。
5:至此,问题转化为判断图中是否存在正环的问题。
参考代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define endl '\n'
typedef pair<int, double> pid;
typedef pair<double, int> pdi;
const int maxn = 5e4+2;
const int N = 5e4+5;
const double eps = 1e-8;
vector<array<int, 4>> p;
int n, m;
int h[N], e[N], ne[N], idx;
double w[N];
queue<int> q;
int st[N];
double dist[N], cnt[N];
void add(int a, int b, double c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
// spfa判负环,板子略
bool spfa();
bool check(double mid)
{
memset(h, -1, sizeof h);
idx=0;
for (auto [a, b, c, d] : p)
{
double ww = log(c) - log(a) + log(mid);
add(b, d, -ww);
}
return spfa();
}
void solve()
{
cin >> n >> m;
p.resize(m);
for (auto &[a, b, c, d] : p)
cin >> a >> b >> c >> d;
double l = 0, r = 1;
while (r - l > eps)
{
double mid = (l + r) * 0.5;
if (check(mid))
l = mid;
else
r = mid;
}
printf("%.8lf",l);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
solve();
return 0;
}