给你n个点,m条边,连接成一个无向图,每个边最初有一个状态(0 or 1)表示是否能够通过,同时给k个开关位于k的顶点上,每次点击开关会使得所有路的状态发生改变,问从1到n的最短路径。 将不同状态分层并添加在两种状态之间转换的路径E - Crystal Switches
题目大意:
解题思路:
看见一个图有多种状态就可以想到经典的分层图模型,个人感觉分层图和扩展域并查集有点像,都是通过扩展集合来维护多种状态之间的关系。
分层图: 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));
}
通过搜索相同状态来转移最短路,在开关节点处要注意同时考虑0,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;
}
# 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;
}