题目链接: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;
}