例1:
题意:
萨格勒布的电车网络由许多交叉路口和连接其中一些的铁路组成。在每个交叉路口都有一个开关,指向从交叉口出来的一个轨道。当有轨电车进入交叉路口时,它只能沿开关指向的方向离开。如果驾驶员想要采取其他方式,他/她必须手动更换开关。
当驾驶员从交叉路口A开车到交叉路口B时,他/她试图选择将最小化他/她必须手动更换开关的次数的路线。
编写一个程序,计算从交叉路口A到交叉路口B所需的最小开关变化次数。
Input:
输入的第一行包含整数N,A和B,由单个空白字符分隔,2 <= N <= 100,1 <= A,B <= N,N是网络中的交叉点数,以及交叉点从1到N编号。
以下N行中的每一行包含由单个空白字符分隔的整数序列。第i行中的第一个数字Ki(0 <= Ki <= N-1)表示从第i个交叉点出来的轨道数。下一个Ki数字表示直接连接到第i个交叉点的交叉点。第i个交叉点中的交换点最初指向列出的第一个交叉点的方向。
Output:
输出的第一行也是唯一一行应包含目标最小数。如果没有从A到B的路由,则该行应包含整数“-1”。
样例输入:
3 2 1
2 2 3
2 3 1
2 1 2
样例输出:
0
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<functional>//greater/less的头文件
using namespace std;
const int maxn = 105;
const int Max = 1e7 + 10;
int a[maxn][maxn];
int n, A, B;
int main()
{
cin >> n >> A >> B;
for (int i = 1; i <= n; i++) { //初始化
for (int j = 1; j <= n; j++) {
if (i == j)a[i][j] = 0;
else a[i][j] = Max;
}
}
int k, t;
for (int i = 1; i <= n; i++) { //赋值
cin >> k;
for (int j = 1; j <= k; j++) {
cin >> t;
if (j == 1)
a[i][t] = 0;
else
a[i][t] = 1;
}
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for (int j = 1; j <= n; j++) {
if (a[i][j] > a[i][k] + a[k][j])
a[i][j] = a[i][k] + a[k][j];
}
if (a[A][B] == Max)
cout << -1 << endl;
else
cout << a[A][B] << endl;
return 0;
}
补:
1、如果要判断负循环,只需加一句:
if(a[i][i]<0)
2、在算法中偶尔初始值会很大,所以要消除加法溢出问题
if(d[i][k]<INF&&d[k][j]<INF)
3、防止如果有负权边出现影响结果
if(p[now][i] == Max)continue;
4、防止重边
p[a][b] = p[b][a] = min(p[a][b], w);