HDU - 6386

dij最短路 + 条件限制
这道题很有意思,加深了我对Dij的理解。
题意很简单,找一条从1到n的最短路,但若是前一条路和后一条路一致,那么就不计算后一条路,不然不一样了就+1,即边权全是1或0,是0是1取决于前一权值是否和当前权值一致。

那么关键点在哪里呢?
对于dij堆优化的理解。
首先,优先队列里存放的到底是什么?
是待选答案。
vis数组起到什么作用?
区分处理完的集合,和待处理数据的集合。
那么优先队列起到的是取出待处理数据中离处理完集合 距离最小的那个。

这看似是非常基础的dij最短路的知识,但在这道题中是一个关键点。

平常dij都有这段

if(!vis[v]&&dis[v] > w+dis[u]){
       dis[v] = w+dis[u];
       q.push(qnode{ v,dis[v]});
}

这里是用以处理好的点的最短路去不停的更新未访问结点的最短路,直到访问过的点的最短路比一个未访问点的最短路长了,那么那个点就一定是到源点的最短路径了(比它短的都更新过它了)

所以存一下边,dij就可以了

#include<iostream>
#include<stdio.h>
#include<string>
#include<cstring>
#include<vector>
#include<stack>
#include<algorithm>
#include<queue>
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin                    \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
typedef long long LL;
typedef pair<int, int> PII;
typedef vector<int> VI;
const int INF=0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-6;

const int N=100010;
const int M=400010;
int head[N];
int top;
int n,m;
struct Edge
{
    int val;
    int to;
    int next;
}edge[M];
void addedge(int a,int b,int c)
{
    edge[top].to=b;
    edge[top].val=c;
    edge[top].next=head[a];
    head[a]=top++;
}
void init()
{
    top=0;
    clr(head,-1);
}

int dis[N];
int vis[N];

struct qnode
{
    int id;
    int pre;
    int dis;
    bool operator <(const qnode &r)const
    {
        return dis>r.dis;
    }
};


void Dij(int start)
{
    clr(vis,0);
    clr(dis,INF);
    priority_queue<qnode> q;
    dis[start] = 0;
    q.push(qnode{start,-1,0});
    while(!q.empty()){
        qnode cur=q.top();
        q.pop();
        int u=cur.id;
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];~i;i=edge[i].next){
            int v=edge[i].to,w=edge[i].val;
            if(!vis[v]&&dis[v]>=dis[u]+(w!=cur.pre)){
                dis[v]=dis[u]+(w!=cur.pre);
                q.push(qnode{v,w,(w!=cur.pre) + dis[u]});
            }
        }
    }
}

int main() {
    while(~scanf("%d%d", &n, &m)) {
        init();
        int u, v, w;
        for(int i=1; i<=m; i++) {
            scanf("%d%d%d", &u, &v, &w);
            addedge(u, v, w);
            addedge(v, u, w);
        }
        Dij(1);
        if(dis[n] == INF)    printf("-1\n");
        else    printf("%d\n", dis[n]);
    }
    return 0;
}
/*

6 6
1 2 2
3 6 2
1 4 3
4 6 3
3 6 2
5 6 2

*/

/*

6 6
1 2 2
3 6 2
1 4 3
4 6 3
3 6 2
5 6 2

*/

猜你喜欢

转载自blog.csdn.net/wyxxzsy/article/details/82889443
hdu