Tyvj1293(新姿势:次短路)

题目链接

分析:
我一开始想了一个自己都可以hack掉的算法:
先来一个朴素spfa
之后循环与终点相连的所有边,
到达终点的距离就是dis[way[i].y]+way[i].v
统计最小的路径和次小的路径,输出答案
竟然过掉了6个点

然后我就暴力搜索,T了7个点,STO

好,我们来正经的
于是我又想了一个做法,每个点都统计一下到达该点的最小距离和次小距离
但这好像不大现实

后来我才发现,这是一道次短路的裸题
又可以学习一种新算法了

具体的做法引用一下BYVOID大牛文章里的一段话:
我们要对一个有向赋权图(无向图每条边可以看作两条相反的有向边)
的顶点S到T之间求次短路径,首先应求出S的单源最短路径
遍历有向图,标记出可以在最短路径上的边,加入集合K
然后枚举删除集合K中每条边,求从S到T的最短路径,
记录每次求出的路径长度值,其最小值就是次短路径的长度
在这里我们认为次短路径长度可以等于最短路径长度,
如果相等,也可以看作是从S到T有不止一条最短路径
如果我们规定求从S到T**大于最短路径长度**的次短路径,
则答案就是每次删边后大于原最短路径的S到T的最短路径长度的最小值

成功AC

这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int INF=0x33333333;
const int N=10001;
int s,t,n,m;
struct node{
    int x,y,nxt,v;
};
node way[N<<2];
int st[N],tot=0,ans1,ans2,dis[N],q[N],tou,wei,pre[N];
bool p[N];

void add(int u,int w,int z)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
    tot++;
    way[tot].x=w;way[tot].y=u;way[tot].v=z;way[tot].nxt=st[w];st[w]=tot;
}

int spfa(int s,int t)
{
    tou=wei=0;
    q[++wei]=s;
    memset(pre,0,sizeof(pre));
    memset(dis,0x33,sizeof(dis));
    dis[s]=0;
    memset(p,1,sizeof(p));
    p[s]=0;
    do
    {
        int r=q[++tou];
        for (int i=st[r];i;i=way[i].nxt)
        {
            if (dis[way[i].y]>dis[r]+way[i].v)
            {
                dis[way[i].y]=dis[r]+way[i].v;
                pre[way[i].y]=i;
                if (p[way[i].y])
                {
                    q[++wei]=way[i].y;
                    p[way[i].y]=0;
                }
            }
        }
        p[r]=1;
    }
    while (tou<wei);
    return dis[t];
}

int spfa2(int s,int t)
{
    tou=wei=0;
    q[++wei]=s;
    memset(dis,0x33,sizeof(dis));
    dis[s]=0;
    memset(p,1,sizeof(p));
    p[s]=0;
    do
    {
        int r=q[++tou];
        for (int i=st[r];i;i=way[i].nxt)
        {
            if (dis[way[i].y]>dis[r]+way[i].v)
            {
                dis[way[i].y]=dis[r]+way[i].v;
                if (p[way[i].y])
                {
                    q[++wei]=way[i].y;
                    p[way[i].y]=0;
                }
            }
        }
        p[r]=1;
    }
    while (tou<wei);
    return dis[t];
}


int main()
{
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for (int i=1;i<=m;i++)
    {
        int u,w,z;
        scanf("%d%d%d",&u,&w,&z);
        add(u,w,z);
    }
    ans1=spfa(s,t);
    if (ans1==INF) {
        printf("He lose his love
");
        return 0;
    }
    ans2=INF;
    for (int i=t;i!=s;i=way[pre[i]].x)   //记录最短路 
    {
        int u=way[pre[i]].v;
        way[pre[i]].v=INF;
        ans2=min(ans2,spfa2(s,t));
        way[pre[i]].v=u;   //别忘了恢复值 
    }
    if (ans2==INF) printf("He will be cursed
");
    else printf("%d
",ans2);
    return 0;   
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673234.html