2010 SDOI 大陆争霸

41 篇文章 0 订阅

题意 :
给出N个点,求1号点到N号点的最短路,每个点有一定数量的保护它的点,需要先遍历所有保护它的点才能经过。
本来想用spfa来着,结果发现死活只有10分……换成dijkstra立马就A了QAQ。
改动下最短路的松弛操作,每次只更新没有被保护节点,到达这个节点后如果有其他城市可以被更新(不再被保护),更新它的dist 为max(dis,dist)。记录dis[i]和dist[i]分别表示 i 城市的可进入时间和到达时间,用num[i]记录一个城市剩余的结界保护数量,每次从堆中取出f,更新 f 所连通节点的dist和 f 所保护节点的 dis ,f 所保护节点的num –,如num为 0 ,就把节点入堆。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m;
const int size = 200100;
int head[size],next[size],dist[size],dis[size];
int map[3010][3010];
int num[3010];
int nu[3010];
bool use[size];
struct dc
{
    int t,d;
}l[size];
int tot = 1;
void build(int f,int t,int d)
{
    l[tot].t = t;
    l[tot].d = d;
    next[tot] = head[f];
    head[f] = tot ++;
}
bool pd(int t)
{
    if(num[t] == 0)
        return true;
    return false;
}
priority_queue<pair < int , int > , vector< pair < int , int > > , greater< pair< int , int >  > >q;
void dijkstra()
{
    memset(dist,127/3,sizeof(dist));
    q.push(make_pair(0,1));
    dist[1] = 0;
    while(!q.empty())
    {
        int f = q.top().second;
        q.pop();
        if(use[f])
            continue;
        use[f] = 1;
        int mx = max(dist[f],dis[f]);
        for(int i = head[f] ; i ; i = next[i])
            if(mx + l[i].d < dist[l[i].t])
            {
                dist[l[i].t] = mx + l[i].d;
                int tmp = max(dist[l[i].t],dis[l[i].t]);
                if(pd(l[i].t))
                    q.push(make_pair(tmp,l[i].t));
            }
        for(int i = 1 ; i <= nu[f] ; i ++)
        {
            int t = map[f][i];
            num[t] --;
            dis[t] = max(dis[t],mx);
            int tmp = max(dist[t],dis[t]);
            if(pd(t))
                q.push(make_pair(tmp,t));
        }
    }
    printf("%d\n",max(dis[n],dist[n]));
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1 ; i <= n ; i ++)
        dist[i] = 214748364;
    for(int i = 1 ; i <= m ; i ++)
    {
        int f,t,d;
        scanf("%d%d%d",&f,&t,&d);
        if(f != t)
            build(f,t,d);
    }
    for(int i = 1 ; i <= n ; i ++)
    {
        int li;
        scanf("%d",&li);
        num[i] = li;
        for(int j = 1 ; j <= li ; j ++)
        {
            int pro;
            scanf("%d",&pro);
            map[pro][++nu[pro]] = i;
        }
    }
    dijkstra();
    return 0;
}

传送门 :
codevs2310
bzoj1922

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值