Timus 1888. Pilot Work Experience

原题: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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值