【JZOJ 4597】 现世斩

来源:互联网 发布:淘宝电脑版网址 编辑:程序博客网 时间:2024/04/30 00:47

Description

异变又发生了,魂魄妖梦作为幻想乡的一名自(cheng)机(guan),主动前去解决异变。
我们用一个n个点、m条边的无向联通图来表示妖梦可选择的路线,妖梦从白玉楼出发,白玉楼被视为编号为1的点,编号为2——n的点是幻想乡的村庄,其中编号为n的村庄发生了异变。
每条边上可能会有一些妖怪袭击人类(然而妖梦是半人半灵),所以对于第i条边,妖梦需要t[i]分钟通过这条路。妖梦带了她的人符[现世斩],可以使所有连接点x的边的通过时间变成1(x可以任意指定)。然而为了保留足够的力量解决异变,妖梦只会用这个符卡一次。妖梦想知道,她到达村庄n的最短时间是多少。
100%:2≤n≤100,000 n-1≤m≤500,000 1≤t[i]≤1,000,000,000
可能有重边和自环,保证能从1到n

Analysis

可以分层跑,跟那道GDOI2016day2T1,基本一样。
或者,有一种更机智的方法。从1和n各跑一次最短路,然后枚举一个中间点被废掉,由于中间点所连出的边被废掉都会变成1,所以再枚举中间点连出去的点u,更新min(dis[1~u])和min(dis[u~n]),取到两个min再加上2.

Code

#include<cstdio>#include<queue>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define efo(i,v) for(int i=last[v];i;i=next[i])using namespace std;typedef long long ll;const int N=100010,M=1000010;const ll INF=2147483647000000;int n,m,tot,to[M],next[M],last[N];ll wei[M],dis[2][N];queue<int> q;bool bz[N];void link(int u,int v,int w){    to[++tot]=v,wei[tot]=w,next[tot]=last[u],last[u]=tot;}void spfa(int S,int p){    fill(dis[p],dis[p]+N,INF);    dis[p][S]=0;    q.push(S);    memset(bz,0,sizeof(bz));    bz[S]=1;    while(!q.empty())    {        int u=q.front();q.pop();        bz[u]=0;        efo(i,u)        {            int v=to[i];            if(dis[p][u]+wei[i]<dis[p][v])            {                dis[p][v]=dis[p][u]+wei[i];                if(!bz[v])                {                    bz[v]=1;                    q.push(v);                }            }        }    }}int main(){    freopen("cut.in","r",stdin);    freopen("cut.out","w",stdout);    int u,v,w;    scanf("%d %d",&n,&m);    tot=1;    fo(i,1,m)    {        scanf("%d %d %d",&u,&v,&w);        if(u==v) continue;        link(u,v,w),link(v,u,w);    }    spfa(1,0);    spfa(n,1);    ll ans=INF;    fo(v,1,n)    {        ll l=INF,r=INF;        efo(i,v)        {            int u=to[i];            l=min(l,dis[0][u]);            r=min(r,dis[1][u]);        }        ans=min(ans,l+r+2);    }    printf("%lld\n",ans);    return 0;}
0 0
原创粉丝点击