csust 第二次省赛选拔 1016旅游 (二维djikstra 很不错的好题)

旅游
题 意:
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;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81590072