原题:Pilot Work Experience
题意:有n次航班以及p个飞行员,每一个飞行员有一个经验值,每个航班需要两名飞行员,且每一次航班的两名飞行员的经验值相差只能为1.读入n次航班的两名飞行员序号,问是否有解。若无解输出-1.若有解,则输出任意两名飞行员经验可能相差的最大值,再把每一位飞行员的经验值输出,如有多解,输出任意一种。
解法:这题有几个坑要注意一下,如果有解,那么要输出的所有飞行员的经验值的方案一定是满足存在两名飞行员的经验值的差为那个最大值。这题很明显是一个最短路,在每一个连通图中,经验值相差的最大值就是最短路中最长的那条路。若图中存在两个或以上的连通图,那么最大值一定为49,解法就是把第一个连通图从1开始正着做一遍bfs(+1),后面的连通图反着从50开始做bfs(-1),那么就是最终解。另外注意一个连通图的每一个节点都要跑一遍bfs,因为如图
在点1和点2跑的bfs的最长路径明显不同
#include<iostream>
using namespace std;
#include <stdlib.h>
#include <cstring>
int n, m;
bool map[100][100] = {0};
int a[100] = {0}, d[100] = {0}, temp[100];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int x, y;
cin >> x >> y;
map[x][y] = 1;
map[y][x] = 1;
}
int tot = 0;
for (int k = 1; k <= m; k++) if (a[k] == 0) {
tot++;
if (tot == 1) {
a[k] = 1;
d[1] = k;
int i = 0, j = 1;
while (i < j) {
i++;
for (int t = 1; t <= m; t++) if (map[d[i]][t]) {
if (abs(a[t]-a[d[i]]) != 1 && a[t] != 0) {
cout << -1 << endl;
return 0;
}
if (a[t] == 0) {
j++;
d[j] = t;
a[t] = 1+a[d[i]];
}
}
}
} else {
a[k] = 50;
d[1] = k;
int i = 0, j = 1;
while (i < j) {
i++;
for (int t = 1; t <= m; t++) if (map[d[i]][t]) {
if (abs(a[t]-a[d[i]]) != 1 && a[t] != 0) {
cout << -1 << endl;
return 0;
}
if (a[t] == 0) {
j++;
d[j] = t;
a[t] = a[d[i]]-1;
}
}
}
}
}
if (tot != 1) cout << "49" << endl;
else {
int max = 0, k;
for (int pp = 0; pp < m; pp++) {
memset(a, 0, sizeof(a));
for (int kk = 1; kk <= m; kk++) {
k = kk+pp;
if (k > m) k = k-m;
if (a[k] != 0) continue;
a[k] = 1;
d[1] = k;
int i = 0, j = 1;
while (i < j) {
i++;
for (int t = 1; t <= m; t++) if (map[d[i]][t]) {
if (abs(a[t]-a[d[i]]) != 1 && a[t] != 0) {
cout << -1 << endl;
return 0;
}
if (a[t] == 0) {
j++;
d[j] = t;
a[t] = 1+a[d[i]];
}
}
}
}
bool flag = false;
for (int i = 1; i <= m; i++) if (a[i] > max) { max = a[i]; flag = true;}
if (flag) {
for (int i = 1; i <= m; i++) temp[i] = a[i];
}
}
for (int i = 1; i <= m; i++) a[i] = temp[i];
max--;
cout << max << endl;
}
for (int i = 1; i < m; i++) cout << a[i] << " ";
cout << a[m] << endl;
}