P2446 [SDOI2010]大陆争霸 (dijkstra)

本篇博客主要介绍了SDOI2010大陆争霸问题,这是一个带限制条件的最短路径问题。在求解过程中,遇到被保护的点时,必须等待所有限制该点的点都被到达后才能继续前进。解决方案包括两种情况:一是可以直接通过未被保护的点;二是需要等待限制点被全部到达后,才可通过被保护的点。关键在于计算通过每个点的最大时刻,即到达时刻和限制解除时刻中取较大者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:https://www.luogu.org/problem/P2446

Description: 

带限制的最短路,途中一些点被其他点限制,当限制该点的点都被到达后方可通过该点。你可以释放无限多个机器人替你跑路。

Solution:

情景一:当前到达的点没有被保护  =>  可以直接通过

情景二:当前到达的点被保护,不能通过 => 在门口等着,直到保护这个点的点都被到达,限制解除,之后方可通过

 通过一个点的时刻 = max(到达该点的时刻,保护该点的所有点都被到达的最后时刻)。

 

Code:

 code1:

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 3100;
int n, m;
int Map[MAXN][MAXN];
int num[MAXN]; //记录有多少个点保护这个点
int protect[MAXN][MAXN];
int dis1[MAXN]; //保护这个点的所有点被摧毁的最后时刻
int dis2[MAXN]; //到达这个点的时刻
int vis[MAXN];
void dijkstra()
{
    memset(dis1, INF, sizeof(dis1)); dis1[1] = 0;
    memset(vis, 0, sizeof(vis));

    int Min, u;
    for(int i = 1; i <= n; i++)
    {
        Min = INF; u = -1;
        for(int j = 1; j <= n; j++)
        {
            if(!vis[j] && Min > max(dis1[j], dis2[j]) && !num[j])
            {
                Min = max(dis1[j], dis2[j]);
                u = j;
            }
        }

        if(u == -1) break;
        vis[u] = 1;

        for(int j = 1; j <= n; j++)
        {
            if(!vis[j])
            {
                if(protect[u][j])
                {
                    num[j]--;
                    dis2[j] = max(dis2[j], Min);
                }
                dis1[j] = min(dis1[j], Min + Map[u][j]);
            }
        }
    }
}
int main()
{
    cin >> n >> m;
    memset(Map, INF, sizeof(Map));
    for(int i = 1; i <= n; i++) Map[i][i] = 0;

    int u, v, w;
    while(m--)
    {
        cin >> u >> v >> w;
        Map[u][v] = min(Map[u][v], w);
    }

    for(int i = 1; i <= n; i++)
    {
        cin >> num[i];
        for(int j = 1; j <= num[i]; j++)
        {
            cin >> v;
            protect[v][i] = 1; //v保护i
        }
    }

    dijkstra();
    cout << max(dis1[n], dis2[n]) << endl;
    return 0;
}

code2:

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int, int>
const int INF = 0x3f3f3f3f;
const int MAXN = 3100;
const int MAXM = 7e4 + 9;
int n, m;
int num[MAXN];//记录都多少个点保护该点
struct Edge
{
    int to, w, nxt;
}edge[MAXM];
int head[MAXN], t = 1;
void init()
{
    memset(head, -1, sizeof(head));
    t = 1;
}
void addEdge(int u, int v, int w)
{
    edge[t].to = v;
    edge[t].w = w;
    edge[t].nxt = head[u];
    head[u] = t++;
}

struct Edge2
{
    int to, nxt;
}edge2[MAXM];
int head2[MAXN], t2 = 1;
void init2()
{
    memset(head2, -1, sizeof(head2));
    t2 = 1;
}
void addEdge2(int u, int v)
{
    edge2[t2].to = v;
    edge2[t2].nxt = head2[u];
    head2[u] = t2++;
}
int dis1[MAXN];
int dis2[MAXN];
int vis[MAXN];
void dijkstra()
{
    memset(dis1, INF, sizeof(dis1)); dis1[1] = 0;
    memset(vis, 0, sizeof(vis));
    memset(dis2, 0, sizeof(dis2));

    priority_queue<pii, vector<pii>, greater<pii> >q;
    q.push({dis1[1], 1});
    while(!q.empty())
    {
        int u = q.top().second;
        q.pop();
        if(vis[u]) continue;
        vis[u] = 1;

        int val = max(dis1[u], dis2[u]); //到达当前点u所花的时间
        for(int i = head[u]; i != -1; i = edge[i].nxt)
        {
            int to = edge[i].to;
            int w = edge[i].w;


            if(!vis[to] && dis1[to] > val + w)
            {
                dis1[to] = val + w;
                if(!num[to])
                {
                    q.push({max(dis1[to], dis2[to]), to});
                }
            }
        }

        for(int i = head2[u]; i != -1; i = edge2[i].nxt)
        {
            int to = edge2[i].to;
            if(num[to])
            {
                num[to]--;
                dis2[to] = max(dis2[to], val);
            }

            if(!num[to]) q.push({max(dis1[to], dis2[to]), to});
        }


    }
}
int main()
{
    cin >> n >> m;
    init();
    init2();
    int a, b, c;
    while(m--)
    {
        cin >> a >> b >> c;
        if(a == b) continue;
        addEdge(a, b, c);
    }

    for(int i = 1; i <= n; i++)
    {
         cin >> num[i];
        for(int j = 1; j <= num[i]; j++)
        {
            cin >> a;
            addEdge2(i, a);
            addEdge2(a, i);
        }
    }

    dijkstra();
    cout << max(dis1[n], dis2[n]) << endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值