[SDOI2010]大陆争霸

带限制的dijkstra,由题意得,每个城市的实际最早进入时间=max(最短路,所有结界点城市的最大最短路)

考虑实现,我们可以记录每个点的入度或是哪个城市保护哪个城市,在维护到某点时判断是否可以进入。若不能进入则continue,能则判断进入该城市后可以解锁哪些新的城市,再将新城市更新压入队列。不同的操作很多,怎么写都行。

时间复杂度O(nlogn)

#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#define M 70010
#include<queue>
#define N 3010
using namespace std;
struct node
{
    int id;
    int d;
    bool operator < (const node &rhs) const
    {
        return rhs.d<d;
    }
};
priority_queue<node> q;
int n,m,head[N],to[M],e,len[M],Next[M];
void buid(int u,int v,int l)
{
    Next[++e]=head[u];head[u]=e;
    to[e]=v;len[e]=l;
}
int s[N][N],vis[N];
int d1[N],d2[N],d[N]; 
void dj()
{
    d1[1]=0;
    q.push((node){1,max(d1[1],d2[1])});
    while(!q.empty())
    {
        node top=q.top();q.pop();
        if(vis[top.id]) continue;
        if(top.d!=max(d1[top.id],d2[top.id])) continue;
        for(int i=head[top.id];i;i=Next[i])
        {
            int j=to[i];
            if(d1[j]>top.d+len[i])
            {
                d1[j]=top.d+len[i];
                if(!d[j]) q.push((node){j,max(d1[j],d2[j])});
            }
        }
        for(int i=1;i<=s[top.id][0];++i)
        {
            d[s[top.id][i]]--;
            if(!d[s[top.id][i]])
            {
                d2[s[top.id][i]]=top.d;
                q.push((node){s[top.id][i],max(d1[s[top.id][i]],d2[s[top.id][i]])});
            }
        }
    }
    printf("%d",max(d1[n],d2[n]));
}
int main()
{
    scanf("%d%d",&n,&m);
    memset(d1,20,sizeof(d1));
    for(int i=1;i<=m;++i)
    {
        int u,v,l;scanf("%d%d%d",&u,&v,&l);
        buid(u,v,l);
    }
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&d[i]);
        for(int j=1;j<=d[i];++j)
        {
            int it;scanf("%d",&it);
            s[it][++s[it][0]]=i;
        }
    }
    dj();
    return 0;
}
原文地址:https://www.cnblogs.com/charlesss/p/10980899.html