• P2446 [SDOI2010]大陆争霸(有限制的最短路)


    题目描述

    幻想历8012年5月12日深夜,斯普林·布拉泽降下神谕:“Trust me, earn eternal life.”克里斯军团士气大增。作为克里斯军团的主帅,你决定利用这一机会发动奇袭,一举击败杰森国。具体地说,杰森国有N个城市,由M条单向道路连接。神谕镇是城市1而杰森国的首都是城市N。你只需摧毁位于杰森国首都的曾·布拉泽大神殿,杰森国的信仰,军队还有一切就都会土崩瓦解,灰飞烟灭。

    为了尽量减小己方的消耗,你决定使用自爆机器人完成这一任务。唯一的困难是,杰森国的一部分城市有结界保护,不破坏掉结界就无法进入城市。而每个城市的结界都是由分布在其他城市中的一些结界发生器维持的,如果想进入某个城市,你就必须破坏掉维持这个城市结界的所有结界发生器。

    现在你有无限多的自爆机器人,一旦进入了某个城市,自爆机器人可以瞬间引爆,破坏一个目标(结界发生器,或是杰森国大神殿),当然机器人本身也会一起被破坏。你需要知道:摧毁杰森国所需的最短时间。

    输入输出格式

    输入格式:

    输入文件的landcraft.in的第一行两个正整数N, M。

    接下来M行,每行三个正整数ui, vi, wi,表示有一条从城市ui到城市vi的单向道路,自爆机器人通过这条道路需要wi的时间。

    之后N行,每行描述一个城市。首先是一个正整数li,维持这个城市结界所使用的结界发生器数目。之后li个1~N之间的城市编号,表示每个结界发生器的位置。如果li = 0,则说明该城市没有结界保护,保证l1 = 0 。

    输出格式:

    输出文件landcraft.out仅包含一个正整数 ,击败杰森国所需的最短时间。

    输入输出样例

    输入样例#1: 复制
    6 6
    1 2 1
    1 4 3
    2 3 1
    2 5 2
    4 6 2
    5 3 2
    0
    0
    0
    1 3
    0
    2 3 5
    输出样例#1: 复制
    5

    说明

    对于20%的数据,满足N≤15,M≤50;

    对于50%的数据,满足N≤500,M≤6,000;

    对于100%的数据,满足N≤3,000,M≤70,000,1≤wi≤108。

    输入数据保证一定有解,且不会存在维持某个城市结界的结界发生器在这个城市内部。

    连接两个城市的道路可能不止一条,也可能存在一个城市自己到自己的道路。





    这种有限制最短路的访问次序恰巧符合Dijkstra的特点,因为每个点只会走一次。

    d1代表到达的实际时间

    d2代表到达他所有的保护器最晚的时间

    d=max(d1,d2) 是实际的时间,可以用来更新别人的

    最后直接一波Dijkstra最短路就好了




     1 #include<iostream>
     2 #include<cstring>
     3 #include<vector>
     4 #include<cstdio>
     5 #define M 70010
     6 #include<queue>
     7 #define N 3010
     8 using namespace std;
     9 struct node
    10 {
    11     int id;
    12     int d;
    13     bool operator < (const node &rhs) const
    14     {
    15         return rhs.d<d;
    16     }
    17 };
    18 priority_queue<node> q;
    19 int n,m,head[N],to[M],e,len[M],Next[M];
    20 void buid(int u,int v,int l)
    21 {
    22     Next[++e]=head[u];head[u]=e;
    23     to[e]=v;len[e]=l;
    24 }
    25 int s[N][N],vis[N];
    26 int d1[N],d2[N],d[N]; 
    27 void dj()
    28 {
    29     d1[1]=0;
    30     q.push((node){1,max(d1[1],d2[1])});
    31     while(!q.empty())
    32     {
    33         node top=q.top();q.pop();
    34         if(vis[top.id]) continue;
    35         vis[top.id]=1;
    36        // if(top.d!=max(d1[top.id],d2[top.id])) continue;
    37         for(int i=head[top.id];i;i=Next[i])
    38         {
    39             int j=to[i];
    40             if(d1[j]>top.d+len[i])
    41             {
    42                 d1[j]=top.d+len[i];
    43                 if(!d[j]) q.push((node){j,max(d1[j],d2[j])});
    44             }
    45         }
    46         for(int i=1;i<=s[top.id][0];++i)
    47         {
    48             d[s[top.id][i]]--;
    49             if(!d[s[top.id][i]])
    50             {
    51                 d2[s[top.id][i]]=top.d;
    52                 q.push((node){s[top.id][i],max(d1[s[top.id][i]],d2[s[top.id][i]])});
    53             }
    54         }
    55     }
    56     printf("%d",max(d1[n],d2[n]));
    57 }
    58 int main()
    59 {
    60     scanf("%d%d",&n,&m);
    61     memset(d1,20,sizeof(d1));
    62     for(int i=1;i<=m;++i)
    63     {
    64         int u,v,l;scanf("%d%d%d",&u,&v,&l);
    65         buid(u,v,l);
    66     }
    67     for(int i=1;i<=n;++i)
    68     {
    69         scanf("%d",&d[i]);
    70         for(int j=1;j<=d[i];++j)
    71         {
    72             int it;scanf("%d",&it);
    73             s[it][++s[it][0]]=i;
    74         }
    75     }
    76     dj();
    77     return 0;
    78 }
     
  • 相关阅读:
    java中的锁
    CAS机制与自旋锁
    volatile关键字的特性及证明
    java中并发下的集合类
    数据库的分库分表
    浅入理解JVM
    99乘法表
    JAVA实现简单的时间刷新使用线程
    线程的优先级
    线程礼让
  • 原文地址:https://www.cnblogs.com/zhangbuang/p/10390113.html
Copyright © 2020-2023  润新知