solution
可以把 Zenyk 当成一个每次修改道路长度后会自动寻找最短路的人机。
那么 Levko 有一个贪心策略,将自己的最短路上的可变边全部调成最小的,将不在 Levko 最短路上的边全部调成最大的。
这样考虑就有几种特殊情况出现。
如下图所示,有一条可变边同时在 Levko 和 Zenyk 的最短路上,那么 Levko 是把它调成 \(l\) 还是 \(r\) 呢。

考虑两种情况。
-
Levko 的距离比 Zenyk 的距离短
- 此时我们可以将这条边调到最小
-
Levko 的距离和 Zenyk 的距离一样或 Levko 的距离大于 Zenyk 的距离
- 此时将这条边的距离调到最大
考虑代码实现
初始把所有边都设为 \(r\),如果 Levko 到这条边的距离小于 Zenyk 到这条边的距离,则把这条边的距离设为 \(l\)。重复执行此操作,直到没有可以改的边。
如果 Levko 赢了,直接输出。
这一次我们还是执行如上操作,但是 Levko 到这条边的距离小于等于 Zenyk 到这条边的距离,就把这条边的距离设为 \(l\),因为这一次要争取平局。
然后判断 Levko 是平局是输即可。
code
代码比较抽象
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int QWQ = 5e5 + 5;
int n, m, k, s1, s2, f, head[QWQ], cnt, qwq114514[QWQ];
int dis1[QWQ], dis2[QWQ];
struct node
{
int s, t, l, r, v;
}a[QWQ];
struct edge
{
int nxt, to, *l;
}qwq[QWQ];
struct QAQ
{
int u, cnt;
bool operator<(const QAQ &Furina) const
{
return cnt > Furina.cnt;
}
};
void addEdge (int u, int v, int *l)
{
qwq[++ cnt].nxt = head[u];
qwq[cnt].to = v;
qwq[cnt].l = l;
head[u] = cnt;
}
void dijstra1(int u)
{
memset(dis1, 0x3f3f3f, sizeof(dis1));
priority_queue<QAQ> q;
dis1[u] = 0;
q.push({u, 0});
while (!q.empty())
{
QAQ v = q.top();
int u = v.u, cnt = v.cnt;
q.pop();
if (dis1[u] != cnt)
{
continue;
}
for (int i = head[u]; i; i = qwq[i].nxt)
{
if(dis1[u] + *qwq[i].l < dis1[qwq[i].to])
{
dis1[qwq[i].to] = min(dis1[qwq[i].to], dis1[u] + *qwq[i].l);
q.push({qwq[i].to, dis1[qwq[i].to]});
}
}
}
}
void dijstra2(int u)
{
memset(dis2, 0x3f3f3f, sizeof(dis2));
priority_queue<QAQ> q;
dis2[u] = 0;
q.push({u, 0});
while (!q.empty())
{
QAQ v = q.top();
int u = v.u, cnt = v.cnt;
q.pop();
if (dis2[u] != cnt)
{
continue;
}
for (int i = head[u]; i; i = qwq[i].nxt)
{
if(dis2[u] + *qwq[i].l < dis2[qwq[i].to])
{
dis2[qwq[i].to] = dis2[u] + *qwq[i].l;
q.push({qwq[i].to, dis2[qwq[i].to]});
}
}
}
}
signed main()
{
cin >> n >> m >> k;
cin >> s1 >> s2 >> f;
for (int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v >> qwq114514[i];
addEdge(u, v, &qwq114514[i]);
}
for (int i = 1; i <= k; i++)
{
cin >> a[i].s >> a[i].t >> a[i].l >> a[i].r;
a[i].v = a[i].r;
addEdge(a[i].s, a[i].t, &a[i].v);
}
for (int i = 1; i <= k; i++)
{
dijstra1(s1);
dijstra2(s2);
if (dis1[a[i].s] < dis2[a[i].s])
{
a[i].v = a[i].l;
}
}
int flag = 0;
do//争取赢
{
flag = 0;
dijstra1(s1);
dijstra2(s2);
for (int i = 1; i <= k; i++)
{
if(dis1[a[i].s] < dis2[a[i].s] && a[i].v == a[i].r)
{
a[i].v = a[i].l;
flag = 1;
}
}
}while(flag);
// cout << dis1[f] << " " << dis2[f] << endl;
if (dis1[f] < dis2[f])
{
cout << "WIN" << endl;
for (int i = 1; i <= k; i++)
{
cout << a[i].v << " ";
}
return 0;
}
flag = 0;
do//争取平局
{
flag = 0;
dijstra1(s1);
dijstra2(s2);
for (int i = 1; i <= k; i++)//
{
if(dis1[a[i].s] <= dis2[a[i].s] + 1 && a[i].v == a[i].r)
{
a[i].v = a[i].l;
flag = 1;
}
}
}while(flag);
if (dis1[f] < dis2[f] + 1)
{
printf("DRAW\n");
for (int i = 1; i <= k; i++)
{
printf("%d ", &a[i].v);
}
}
else cout << "LOSE";
}