Acwing 4275. Dijkstra序列(Dijkstra迪杰斯特拉)()

https://www.acwing.com/problem/content/description/4278/

Dijkstra 算法是非常著名的贪心算法之一。

它用于解决单源最短路径问题,即指定一个特定源顶点,求该顶点到给定图的所有其他顶点的最短路径。

它由计算机科学家 Edsger W. Dijkstra 于 1956 年构思并在三年后出版。

在该算法中,我们需要不断维护一个包含最短路径树中顶点的集合。

在每一步中,我们找到一个尚未在集合内且与源顶点距离最小的顶点,并将其收于集合中。

因此,通过 Dijkstra 算法,我们可以逐步生成一个有序的顶点序列,我们称之为 Dijkstra 序列。

对于一个给定的图,可能有多个 Dijkstra 序列。

例如,{5,1,3,4,2} 和 {5,3,1,2,4} 都是给定图的 Dijkstra 序列。

注意,序列中的第一个顶点即为指定的特定源顶点。

你的任务是检查给定的序列是否是 Dijkstra 序列。

输入格式
第一行包含两个整数 N 和 M,表示图中点和边的数量。

点的编号 1N。

接下来 M 行,每行包含三个整数 a,b,c,表示点 a 和点 b 之间存在一条无向边,长度为 c。

再一行包含整数 K,表示需要判断的序列个数。

接下来 K 行,每行包含一个 1N 的排列,表示一个给定序列。

输出格式
共 K 行,第 i 行输出第 K 个序列的判断,如果序列是 Dijkstra 序列则输出 Yes,否则输出 No。

数据范围
1≤N≤1000,
1≤M≤105,
1≤a,b≤N,
1≤c≤100,
1≤K≤100,
保证给定无向图是连通图,
保证无重边和自环(官网没提,但是经实测,官网数据符合此条件)。

输入样例:
5 7
1 2 2
1 5 1
2 3 1
2 4 1
2 5 2
3 5 1
3 4 1
4
5 1 3 4 2
5 3 1 2 4
2 3 4 5 1
3 2 1 5 4
输出样例:
Yes
Yes
Yes
No
#include<bits/stdc++.h>
using namespace std;
const int N=2002;
int n,m,q,a[N],dist[N],f[N][N];
bool vis[N];
bool dij(int x)
{
    memset(dist,127,sizeof dist);
    memset(vis,0,sizeof vis);
    dist[x]=0;
    vis[x]=1;
    for(int i=1;i<=n;i++)
    {
        int t=a[i];
        vis[t]=1;
        for(int j=1;j<=n;j++)
            if(!vis[j]&&dist[j]<dist[t]) return 0;
        for(int j=1;j<=n;j++)
            if(dist[j]>dist[t]+f[t][j]) dist[j]=dist[t]+f[t][j];
    }
    return 1;
}
int main()
{
    cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
    cin>>n>>m;
    memset(f,127,sizeof f);//为啥么一定得是127
    while(m--)
    {
        int x,y,z;
        cin>>x>>y>>z;
        f[x][y]=f[y][x]=z;
    }
    int q;
    cin>>q;
    while(q--)
    {
        for(int i=1;i<=n;i++)
            cin>>a[i];
        if(dij(a[1])) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}
————————

https://www.acwing.com/problem/content/description/4278/

Dijkstra 算法是非常著名的贪心算法之一。

它用于解决单源最短路径问题,即指定一个特定源顶点,求该顶点到给定图的所有其他顶点的最短路径。

它由计算机科学家 Edsger W. Dijkstra 于 1956 年构思并在三年后出版。

在该算法中,我们需要不断维护一个包含最短路径树中顶点的集合。

在每一步中,我们找到一个尚未在集合内且与源顶点距离最小的顶点,并将其收于集合中。

因此,通过 Dijkstra 算法,我们可以逐步生成一个有序的顶点序列,我们称之为 Dijkstra 序列。

对于一个给定的图,可能有多个 Dijkstra 序列。

例如,{5,1,3,4,2} 和 {5,3,1,2,4} 都是给定图的 Dijkstra 序列。

注意,序列中的第一个顶点即为指定的特定源顶点。

你的任务是检查给定的序列是否是 Dijkstra 序列。

输入格式
第一行包含两个整数 N 和 M,表示图中点和边的数量。

点的编号 1N。

接下来 M 行,每行包含三个整数 a,b,c,表示点 a 和点 b 之间存在一条无向边,长度为 c。

再一行包含整数 K,表示需要判断的序列个数。

接下来 K 行,每行包含一个 1N 的排列,表示一个给定序列。

输出格式
共 K 行,第 i 行输出第 K 个序列的判断,如果序列是 Dijkstra 序列则输出 Yes,否则输出 No。

数据范围
1≤N≤1000,
1≤M≤105,
1≤a,b≤N,
1≤c≤100,
1≤K≤100,
保证给定无向图是连通图,
保证无重边和自环(官网没提,但是经实测,官网数据符合此条件)。

输入样例:
5 7
1 2 2
1 5 1
2 3 1
2 4 1
2 5 2
3 5 1
3 4 1
4
5 1 3 4 2
5 3 1 2 4
2 3 4 5 1
3 2 1 5 4
输出样例:
Yes
Yes
Yes
No
#include<bits/stdc++.h>
using namespace std;
const int N=2002;
int n,m,q,a[N],dist[N],f[N][N];
bool vis[N];
bool dij(int x)
{
    memset(dist,127,sizeof dist);
    memset(vis,0,sizeof vis);
    dist[x]=0;
    vis[x]=1;
    for(int i=1;i<=n;i++)
    {
        int t=a[i];
        vis[t]=1;
        for(int j=1;j<=n;j++)
            if(!vis[j]&&dist[j]<dist[t]) return 0;
        for(int j=1;j<=n;j++)
            if(dist[j]>dist[t]+f[t][j]) dist[j]=dist[t]+f[t][j];
    }
    return 1;
}
int main()
{
    cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
    cin>>n>>m;
    memset(f,127,sizeof f);//为啥么一定得是127
    while(m--)
    {
        int x,y,z;
        cin>>x>>y>>z;
        f[x][y]=f[y][x]=z;
    }
    int q;
    cin>>q;
    while(q--)
    {
        for(int i=1;i<=n;i++)
            cin>>a[i];
        if(dij(a[1])) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
    return 0;
}