现世斩

来源:互联网 发布:淘宝店铺企业店铺入口 编辑:程序博客网 时间:2024/04/29 19:32

题目

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

数据范围:
40%:n≤1000 m≤5000
100%:2≤n≤100,000 n-1≤m≤500,000 1≤t[i]≤1,000,000,000
可能有重边和自环,保证能从1到n。


剖解题目:一个图,保证1可以联通n,每条边有一定权值。可以选择一个点,让与它相连的所有的边都变为1,求在这样情况下1到n的最短路径


思路:最短路径类问题,考虑转化。


解法:
40%:暴力枚举点,每次一个最短路。
100%:如果选择这个点,则后来的最短路径一定会经过这点,显然。那么我们只需要判断起点与终点到与这个点相连的两条点的最短路径即可。
分别以起点与终点跑一次最短路,枚举这个点,再枚举两个与这个点相连的点,判断从起点到其中一个与终点到另一个的和再加上2是否最优,更新答案。


代码:

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define ll long longusing namespace std;const int maxn=100005,maxm=500005;struct cy{    ll t;    int u,v;}a[maxm];int n,m,fre[maxn],next[2*maxm],go[2*maxm],num;ll val[2*maxm],dis[maxn],far[maxn],o;void add(int x,int y,ll z){    ++num;    go[num]=y;    next[num]=fre[x];    fre[x]=num;    val[num]=z;}void spfa1(int x){    bool bz[maxn];    memset(bz,0,sizeof(bz));    bz[x]=true;    int h=0,t=1,d[maxn*2],mo=maxn*2-5;    memset(d,0,sizeof(d));    d[1]=x;    memset(dis,127,sizeof(dis));    o=dis[0];    dis[x]=0;    while (h!=t)    {        h=h%mo+1;        int u=d[h];        bz[u]=false;        int i=fre[u];        while (i!=0){            if (dis[go[i]]>dis[u]+val[i]) {                dis[go[i]]=dis[u]+val[i];                if (!bz[go[i]]) {                    t=t%mo+1;                    d[t]=go[i];                    bz[go[i]]=true;                }            }            i=next[i];        }    }}void spfa2(int x){    bool bz[maxn];    memset(bz,0,sizeof(bz));    bz[x]=true;    int h=0,t=1,d[maxn*2],mo=maxn*2-5;    memset(d,0,sizeof(d));    d[1]=x;    memset(far,127,sizeof(far));    far[x]=0;    while (h!=t)    {        h=h%mo+1;        int u=d[h];        bz[u]=false;        int i=fre[u];        while (i!=0){            if (far[go[i]]>far[u]+val[i]) {                far[go[i]]=far[u]+val[i];                if (!bz[go[i]]) {                    t=t%mo+1;                    d[t]=go[i];                    bz[go[i]]=true;                }            }            i=next[i];        }    }}ll search(int x){    ll ans=1e15;    fo(x,1,n){        int i=fre[x];        while (i){            int u=go[i];            if (dis[u]!=o){                int j=fre[x];                while (j){                    if (j==i){                        j=next[j];                        continue;                    }                    int v=go[j];                    if (far[v]!=u){                        if (dis[u]+far[v]+2<ans) ans=dis[u]+far[v]+2;                    }                j=next[j];                }            }            i=next[i];        }    }    return ans;}int main(){    freopen("cut.in","r",stdin);    freopen("cut.out","w",stdout);    scanf("%d%d",&n,&m);    int k=n;    fo(i,1,m) {        scanf("%d%d%lld",&a[i].u,&a[i].v,&a[i].t);        if (a[i].u!=a[i].v) {            add(a[i].u,a[i].v,a[i].t);            add(a[i].v,a[i].u,a[i].t);          }    }    spfa1(1);    spfa2(n);    printf("%lld",search(n));    fclose(stdin); fclose(stdout);}

这里写图片描述

0 0
原创粉丝点击