【JZOJ4597】现世斩

Description

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

Solution

显然把原图分成三层,跑一次最短路即可。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define N 300001
#define M 4000001
#define ll long long
using namespace std;
int to[M],next[M],last[M],val[M],num=0;
void link(int x,int y,int c)
{
    num++;
    to[num]=y;
    next[num]=last[x];
    last[x]=num;
    val[num]=c;
}
int d[M];
ll dis[N];
bool vis[N];
void spfa(int s)
{
    memset(dis,60,sizeof(dis));
    dis[1]=0;
    vis[1]=true;
    d[1]=1;
    int l=0,r=1;
    while(l<r)
    {
        int x=d[++l];
        for(int i=last[x];i;i=next[i])
        {
            int v=to[i];
            if(dis[x]+val[i]<dis[v])
            {
                dis[v]=dis[x]+val[i];
                if(!vis[v])
                {
                    vis[v]=true;
                    d[++r]=v;
                }
            }
        }
        vis[x]=false;
    }
}
int main()
{
    freopen("cut.in","r",stdin);
    freopen("cut.out","w",stdout);
    int n,m;
    cin>>n>>m;
    fo(i,1,m)
    {   
        int u,v,w;
        scanf("%d %d %d",&u,&v,&w);
        if(u!=v)
        {
            link(u,v,w);
            link(v,u,w);
            link(u,v+n,1);
            link(u+n,v+n*2,1);
            link(v,u+n,1);
            link(v+n,u+n*2,1);
            link(u+n*2,v+n*2,w);
            link(v+n*2,u+n*2,w);
        }
    }
    spfa(1);
    cout<<dis[n*3];
}
posted @ 2016-07-18 10:00  sadstone  阅读(53)  评论(0)    收藏  举报