(AtCoder Beginner Contest 277)E(分层图+最短路 or bfs搜两种状态)

E - Crystal Switches


题目大意:

给你n个点,m条边,连接成一个无向图,每个边最初有一个状态(0 or 1)表示是否能够通过,同时给k个开关位于k的顶点上,每次点击开关会使得所有路的状态发生改变,问从1到n的最短路径。


解题思路:

  1. 分层图
    看见一个图有多种状态就可以想到经典的分层图模型,个人感觉分层图和扩展域并查集有点像,都是通过扩展集合来维护多种状态之间的关系。
    分层图:
	for (int i = 1; i <= m; ++i) {
		int a, b, c;
		cin >> a >> b >> c;
		if (c) {
			e[a].push_back(mk_p(b, c));//状态1的路径在同一层[1,n]
			e[b].push_back(mk_p(a, c));
		} else {//状态0的路径在同一层[1+n,n+n]
			e[a+n].push_back(mk_p(b+n, c^1));
			e[b+n].push_back(mk_p(a+n, c^1));
		}
	}
	
	for(int i = 1;i <= k;++i)//开关,连接两种状态的通道
        {
		int x;
		cin>>x;
		e[x].push_back(mk_p(x+n,0));//连接状态1和状态0的路径
		e[x+n].push_back(mk_p(x,0));
	}

将不同状态分层并添加在两种状态之间转换的路径

  1. bfs+两种状态搜索:
    通过搜索相同状态来转移最短路,在开关节点处要注意同时考虑0,1两种状态
    剩下的就和最短路差不多了

代码实现:

  1. 分层图
#include<bits/stdc++.h>
using namespace std;
# define int long long
# define endl "\n"
# define mk_p(a,b) make_pair(a,b)
const int N = 2e5 + 10, inf = 0x3f3f3f3f;
typedef pair<int, int> node;
vector<node> e[N<<1];
int dix[N<<1];
int vis[N<<1];
int n, m, k;
void dijstra(int st){
	for(int i = 1;i <= 2*n;++i){
		dix[i] = inf;
		vis[i] = 0;
	}
	priority_queue<node,vector<node>,greater<node> > q;
	q.push(mk_p(-inf,st));
	dix[st] = 0;
	while(!q.empty()){
		int u = q.top().second;
		q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(auto [v,w]:e[u]){
			if(dix[v]>dix[u]+w){
				dix[v] = dix[u]+w;
				q.push(mk_p(dix[v],v));
			}
		}
	}
}


void solve() {

	cin >> n >> m >> k;
	for (int i = 1; i <= m; ++i) {
		int a, b, c;
		cin >> a >> b >> c;
		if (c) {
			e[a].push_back(mk_p(b, c));
			e[b].push_back(mk_p(a, c));
		} else {
			e[a+n].push_back(mk_p(b+n, c^1));
			e[b+n].push_back(mk_p(a+n, c^1));
		}
	}
	
	for(int i = 1;i <= k;++i){
		int x;
		cin>>x;
		e[x].push_back(mk_p(x+n,0));
		e[x+n].push_back(mk_p(x,0));
	}
	
	dijstra(1);
	
	if(dix[n]==inf && dix[2*n] == inf) cout<<-1<<endl;
	else cout<<min(dix[n],dix[2*n])<<endl;


}
int tt;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	tt = 1;
//	cin >> tt;
	while (tt--) solve();


	return 0;
}
  1. bfs
# include<iostream>
# include<bits/stdc++.h>
using namespace std;
# define int long long
# define endl "\n"
const int N = 5e5 + 10, inf = 0x3f3f3f3f;
typedef pair<int, int> node;
# define mk_p(a,b) make_pair(a,b)
vector<node> e[N];
int dix[N][2];//dix[u][0],dix[u][1]表示在两种状态下的最短路
int a[N];//开关
void solve() {
	int n, m, k;
	cin >> n >> m >> k;
	for (int i = 1; i <= m; ++i) {
		int a, b, c;
		cin >> a >> b >> c;
		e[a].push_back(mk_p(b, c));
		e[b].push_back(mk_p(a, c));
	}
	for (int i = 1; i <= k; ++i) {
		int x;
		cin >> x;
		a[x]  = 1;
	}
	queue<node> q;
	q.push(mk_p(1, 1));
	memset(dix, 0x3f, sizeof dix);
	dix[1][1] = 0;

	while (!q.empty()) {
		int u = q.front().first;
		int st = q.front().second;
		q.pop();
		if (!a[u]) {
			for (auto [v, st2] : e[u]) {
				if (st2 != st) continue;
				if (dix[v][st2] > dix[u][st] + 1) {
					dix[v][st2] = dix[u][st] + 1;
					q.push(mk_p(v, st2));
				}
			}
		} else {
			for (auto [v, st2] : e[u]) {
				if (st2 != st) {
					if (dix[v][st2] > dix[u][st] + 1) {
						dix[v][st2] = dix[u][st] + 1;
						q.push(mk_p(v, st2));
					}
				} else if (dix[v][st2] > dix[u][st] + 1) {
					dix[v][st2] = dix[u][st] + 1;
					q.push(mk_p(v, st2));
				}
			}
		}
	}

	int minn = inf;
	if (dix[n][0] != -1) minn = min(dix[n][0], minn);
	if (dix[n][1] != -1) minn = min(dix[n][1], minn);
	if (minn == inf)cout << -1 << endl;
	else cout << minn << endl;
}
int tt;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	tt = 1;
//	cin >> tt;
	while (tt--) solve();


	return 0;
}
posted @ 2022-11-13 20:33  empty_y  阅读(216)  评论(0)    收藏  举报