现在明确我们的目的:能赢就选择赢的方案,否则尝试平局;并不是求和对方差值更大的方案。
考虑一个赢/平局的方案,考虑每一条边,没有被任何一个经过,那么调整到任何值都是无所谓的;如果仅被 经过,调整到 是更优的;如果仅被 经过,调整到 是更优的;如果同时被 经过,那么一定是一个平局的方案,把这条边改得更小还会使 经过这里,如果把这条边改得更大反而可能让 走其他路从而变成一个 赢的方案,如果不存在让 赢的方案再把它改成 ,也就是尽可能地让 一起走到这里,促成平局。
综上所述,一定存在一个最优方案使得每条边的权值要不然为 ,要不然为 。
考虑如何让 赢:对于一条边 :
-
若 ,那么 一定不会走这条路,因为走到这条路之后和 的最优路线重合,一定不会赢,所以改成 让 走这条路的开销更大;
-
若 ,同理, 走这条路会使 赢,那么 不会走这条路,改成 让 走这条路的开销更小。
现在判断完了 能不能赢,如果不能赢就尽可能平局,和上面的思路基本一致:
-
若 ,那么 一定不会走这条路,因为走到这条路之后和 的最优路线重合,一定不会平局,所以改成 让 走这条路的开销更大;
-
若 ,同理, 走这条路会平局或 赢 ,那么 不会走这条路,改成 让 走这条路的开销更小。
先钦点所有的边都是 ,每次跑 Dijkstra 然后看哪些边要改权值就改,没有边权值要改时再判断,易做到 .
实际上可以在最短路每次松弛的时候判断当前边的权值是多少,时间复杂度 .
#include<iostream>
#include<cstdio>
#include<queue>
#define int long long
typedef long long ll;
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T>
T& read(T& r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = r * 10 + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
const int N = 200010;
const ll INF = 0x7fffffffffffffff;
int n, m, k;
int s1, s2, t;
ll dis[N];
struct Edge {
int to, val1, val2, id;
bool fl;
Edge(int x = 0, int y = 0, int z = 0, int p = 0) { to = x; val1 = y; val2 = z; id = p; }
};
int ans[N];
std::vector<Edge>vec[N];
std::queue<int>q;
void Dij(int s1, int s2, int fl) {
for(int i = 1; i <= n; ++i) dis[i] = INF;
dis[s1] = 1; dis[s2] = 0;
q.push(s1); q.push(s2);
while(!q.empty()) {
int x = q.front(); q.pop();
for(Edge &e : vec[x]) {
int v = e.to, w = (e.fl = ((dis[x]&1) == fl)) ? e.val1 : e.val2;
if(dis[v] > dis[x] + w) {
dis[v] = dis[x] + w;
q.push(v);
}
}
}
}
signed main() {
read(n); read(m); read(k);
read(s1); read(s2); read(t);
for(int i = 1; i <= m; ++i) {
int u, v, l; read(u); read(v); read(l);
vec[u].push_back(Edge(v, l<<1, l<<1, 0));
}
for(int i = 1; i <= k; ++i) {
int u, v, l, r; read(u); read(v); read(l); read(r);
vec[u].push_back(Edge(v, l<<1, r<<1, i));
}
Dij(s1, s2, 1);
if(dis[t] & 1) {
puts("WIN");
for(int i = 1; i <= n; ++i)
for(Edge e : vec[i])
ans[e.id] = e.fl ? e.val1 : e.val2;
for(int i = 1; i <= k; ++i) printf("%lld ", ans[i]/2);
}
else {
Dij(s2, s1, 0);
if(!(dis[t]&1)) {
puts("DRAW");
for(int i = 1; i <= n; ++i)
for(Edge e : vec[i])
ans[e.id] = e.fl ? e.val1 : e.val2;
for(int i = 1; i <= k; ++i) printf("%lld ", ans[i]/2);
}
else {
puts("LOSE");
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?