2018.10.29-dtoj-4001-分身术(phantom)

题目描述:

题目背景:当您再次回到机房时已经是中午了,于是您决定去吃饭。

从机房到食堂的地图可以简化为一张
n 个点,m 条边的有向图,通过每条边需要一定的时间。机房在1号节点,食堂在n号节点。膜法师hercier 使用结界将食堂和一些点封锁了起来使其无法通过,如果想通过某个节点,你就必须破坏掉维持这个节点结界的所有结界发生器。幸运的是,你在上一题的未知森林里领悟了分身术,你可以分出无限多的分身去破坏结界发生器,normalgod 想知道你最早什么时候能到达食堂,请你写个程序告诉他。(破坏瞬间完成,分身移动速度与本体相同)

输入:

第一行2 个整数,分别表示n,m  。

之后m 行每行三个整数a,b,c 表示a 到b有一条需要走c分钟的边。
之后n行每行一个正整数k kk表示维持这个节点结界的结界发生器数目。

之后k 个1−n 之间的节点编号,表示每个结界发生器的位置。

输出

到达食堂的最早时间,永远不能到达输出−1 。

数据范围:

对于20% 的数据,满足 n≤15,m≤50 n≤15,m≤50n≤15,m≤50

对于50% 的数据,满足 n≤500,m≤6000 
对于另20% 的数据,满足k=0对于100% 的数据,满足n≤3000,m≤70000,1≤c≤108

算法标签:dijk&拓扑

思路:

把限制转化拓扑序,每次按照拓扑序入队列,开个数组记录通向这个点的分身所需要的最大值,dijk套拓扑,思路不难要坚定信念吧,不要怀疑自己....

啊...我的题解越来越短越来越失去观赏度了咦...

以下代码:

 

#include<bits/stdc++.h>
#define il inline
#define LL long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=3005,M=70005;const LL inf=1e18;
int n,m,ne[M],head[N],to[M],w[M],in[N],ne1[M],head1[N],to1[M],cnt;
LL d[N],ma[N];bool vis[N],tag[N];
struct node{int x;LL d;bool operator<(const node&t1)const{return d>t1.d;};};priority_queue<node> q;
il int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch^48;_()x=(x<<1)+(x<<3)+(ch^48);return f*x;}
il void insert(int x,int y,int z){ne[++cnt]=head[x];head[x]=cnt;to[cnt]=y;w[cnt]=z;}
il void ins(int x,int y){ne1[++cnt]=head1[x];head1[x]=cnt;to1[cnt]=y;}
il void dijk(){
    for(int i=1;i<=n;i++)d[i]=inf;d[1]=0;q.push((node){1,0});
    while(!q.empty()){
        node now=q.top();q.pop();
        if(vis[now.x])continue;vis[now.x]=1;
        for(int i=head1[now.x];i;i=ne1[i]){
            ma[to1[i]]=max(d[now.x],ma[to1[i]]);
            if(--in[to1[i]]==0&&tag[to1[i]]){
                d[to1[i]]=max(d[to1[i]],ma[to1[i]]);
                q.push((node){to1[i],d[to1[i]]});
            }
        }
        for(int i=head[now.x];i;i=ne[i]){
            if(d[to[i]]<d[now.x]+(LL)w[i]&&ma[to[i]]<d[now.x]+(LL)w[i])continue;
            d[to[i]]=d[now.x]+(LL)w[i];d[to[i]]=max(d[to[i]],ma[to[i]]);tag[to[i]]=1;
            if(in[to[i]]==0)q.push((node){to[i],d[to[i]]});
        }    
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        insert(x,y,z);
    }bool pd=0;cnt=0;
    for(int i=1;i<=n;i++){
        int k=read();
        while(k--){
        int x=read();if(i==1&&x==1){puts("-1");pd=1;}
        ins(x,i);in[i]++;
        }
    }
    if(pd)return 0;
    dijk();if(d[n]==inf){puts("-1");}else printf("%lld\n",d[n]);
  return 0;
}
View Code

 

posted @ 2018-10-29 18:31  Jessiejzy  阅读(197)  评论(0编辑  收藏  举报