[SDOI2010]大陆争霸(最短路)

[SDOI2010]大陆争霸(luogu)

Solution

题目保证一定有解,即若从一个城市的每个结节发生器向这个城市连一条有向边,设构成的图为G1,则G1上没有环

可以看出拓扑的思想

设原图为G2

我们需要在G2上跑一种最短路,使若从G1上有一条路径从 x 到 y ,则不能用 y 更新 x 的值

可以结合拓扑和 Dijkstra 

Code

#include <cstdio>
#include <cstdlib>
#include <queue>
#include <cstring>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
const int N=3e3+10,M=14e4+10;
int head[N],ver[M],nxt[M],tot;
int u,v,n,m,ru[N];
ll edge[M],w,real[N],dis[N];
vector <int> son[N];
bool vis[N];
struct node
{
    int u;
    ll w;
    bool operator <(const node &o)const
    {
        return w>o.w;
    }
};
priority_queue <node> q;
void dij()
{
    memset(dis,0x7f,sizeof(dis));
    dis[1]=real[1]=0;
    q.push((node){1,0});
    while(!q.empty())
    {
        int u=q.top().u;
        q.pop();
        if(vis[u]) continue;
        vis[u]=true;
        ll now=max(dis[u],real[u]);
        for(int i=head[u],v;i;i=nxt[i])
            if(dis[v=ver[i]]>now+edge[i])
            {
                dis[v]=now+edge[i];
                if(ru[v]==0) q.push((node){v,max(dis[v],real[v])});
            }
        int size=son[u].size();
        for(int i=0;i<size;i++)
        {
            int v=son[u][i];
            real[v]=max(real[v],now);
            if(--ru[v]==0) q.push((node){v,max(dis[v],real[v])});
        }
    }
}
void add(int u,int v,int w)
{
    ver[++tot]=v,nxt[tot]=head[u],edge[tot]=w,head[u]=tot;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++)
    {
        scanf("%d%d%lld",&u,&v,&w);
        add(u,v,w);
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&ru[i]);
        for(int j=0;j<ru[i];j++)
        {
            scanf("%d",&u);
            son[u].push_back(i);
        }
    }
    dij();
    printf("%lld\n",max(real[n],dis[n]));
    return 0;
}

 

posted @ 2020-03-10 07:52  hsez_cyx  阅读(173)  评论(0)    收藏  举报