旅游
题 意:
db爱好运动,但是单纯的运动会使得他很枯燥,现在他想边跑步边看风景。已知现在有n个风景点(编号为1号~n号),同时有m条道路将这n个风景点连接起来。
这些风景点总共有3类:A,B,C;为了方便表示,我们令 A=0,B=1,C=2。db一开始在1号风景点(可以为A,B,C类)。现在db想在跑步的过程中经过至少一个B类风景点的同时至少经过一个C类风景点,最后再回到1号风景点。现在db想要在尽可能短的时间内跑步结束(因为他要去找小姐姐了),你能帮他找出一条路程最短同时满足题目条件的路径吗?
数据范围:
第一行两个整数,n和m。n代表风景点个数,m代表风景点之间边数(保证无重边,所有点是联通的)
第二行n个整数,代表是哪一类风景点(0,1,2)三种。
接下来m行,每行三个整数(u,v,w)代表u和v风景点间距离为w。
(2<=n<=200,000),(2<=m<=200,000),(1<=w<=1,000,000)
输出样例:
5 6
0 1 0 2 1
1 2 1
2 3 2
3 4 1
4 5 1
1 4 3
2 5 1
输出样例:
6
思 路:以前开一维的d[j],表示从i除法到达j的最短距离,这次可以在加一维用来储存状态,状压思想。然后跑一个dijkstra 每次取出最小的取更新,然后维护最小值的时候,维护一下状态转移。
收 获:第一道二维dijkstra,明白了多维dijstra的写法。
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 2e5+5;
struct node{
int w,v,sta;
bool operator<(const node q)const{
return w>q.w;
}
};
struct edge{
int to,cost;
};
vector<edge> G[maxn];
int d[maxn][8];
bool vis[maxn][8];
int a[maxn];
int n,m;
void dij(int s){
priority_queue<node> que;
memset(d,INF,sizeof(d));
d[s][(1<<a[s])] = 0;
que.push(node{0,s,(1<<a[s])});
while(que.size()){
node no = que.top();que.pop();
int v=no.v,sta = no.sta;
if(vis[v][sta]) continue;
vis[v][sta] = true;
for(int i=0;i<G[v].size();i++){
edge e = G[v][i];
if(d[e.to][sta|(1<<a[e.to])] > d[v][sta] + e.cost){
d[e.to][sta|(1<<a[e.to])] = d[v][sta] + e.cost;
que.push(node{d[e.to][sta|(1<<a[e.to])],e.to,sta|(1<<a[e.to])});
}
}
}
}
int main(){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=0;i<m;i++){
int u,v,cost;
scanf("%d %d %d",&u,&v,&cost);
G[u].push_back(edge{v,cost});
G[v].push_back(edge{u,cost});
}
dij(1);
printf("%d\n",min(d[1][6],d[1][7]));
return 0;
}