D. Colored Portals (EduRound 169 (Rated for Div. 2))(二分图论最短路)

D. Colored Portals

在这里插入图片描述

思路:

还是很好的题。
枚举,找规律,发现总共6种颜色,对于一种颜色只有唯一的另一种颜色不能直接到达(BG -RY BR-GY BY-GR),而只需要找到任意一个不是这两种颜色的城市(即只有一个共同颜色的剩余四种城市),就可以作为中转。后面就很简单了。
如果x,y可以直接到达,那么最短距离就是|x-y|
否则在只有一个共同颜色的城市中找最近的中转点:
1.如果[x,y]内有中转点,那么最短距离依旧是|x-y|
2.否则在[0,x]和[y,n]中二分查找最接近x、y的点作为中转点
简化一下这个过程,直接找到大于等于x的最小点小于x的最大点作为中转点即可。

代码:
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 0x3f3f3f3f;

unordered_map<string, int> CI;
vector<int> c[6];  //升序维护6种颜色城市编号
vector<int> ys;   //维护每种城市的颜色

void init() {
	CI["BG"] = 0;
	CI["BR"] = 1;
	CI["BY"] = 2;
	CI["GR"] = 3;
	CI["GY"] = 4;
	CI["RY"] = 5;
}
const int cn[6] = {5, 4, 3, 2, 1, 0};  //不能直接到达的颜色
const int co[6][4] = {{1, 2, 3, 4}, {0, 2, 3, 5}, {0, 1, 4, 5}, {0, 1, 4, 5}, {0, 2, 3, 5}, {1, 2, 3, 4}}; //有一个相同颜色

void solve() {
	int n, q;
	cin >> n >> q;
	ys.clear();
	ys.resize(n + 1);
	for (int i = 0; i < 6; ++i) c[i].clear();
	for (int i = 1; i <= n; ++i) {
		string c1;
		cin >> c1;
		ys[i] = CI[c1];
		c[CI[c1]].push_back(i);
	}

	while (q--) {
		int i, j;
		cin >> i >> j;
		if (ys[i] != cn[ys[j]])
			cout << abs(i - j) << endl;
		else {
			// 二分搜索,查找最靠近i和j的颜色与i,j都不同的节点k
			int minDist = MAXN;
			for (int color : co[ys[i]]) {
				// 查找大于等于i的最小点(it)作为中转点
				auto it = lower_bound(c[color].begin(), c[color].end(), i);
				if (it != c[color].end()) {
					int k2 = *it;
						minDist = min(minDist, abs(i - k2) + abs(j - k2));
				}
				// 小于i的最大点(it的前一个点)作为中转点
				if (it != c[color].begin()) {
					int k1 = *prev(it);
						minDist = min(minDist, abs(i - k1) + abs(j - k1));
				}
			}
			cout << (minDist >= MAXN ? -1 : minDist) << endl;
		}
	}
}

int main() {
	cin.tie(0)->ios::sync_with_stdio(0);
	init();
	int T;
	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值