CF360E Levko and Game解题笔记

原题链接

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";
}
posted @ 2025-10-30 11:49  Luowj  阅读(21)  评论(0)    收藏  举报