题目大意
给你n个点(n<=1000),m条有向边,求点a到点b的最短路,如果没有输出-1.
这里面有一个条件,你可以将m条边中任意一条边的权值整除2
题解
比赛的时候,一直没想到如何优化,比赛完之后,大佬对我说,这么简单的最短路都不会,QAQ…, 然后跟我说了一下思路,问我最短路堆优化是不是每一次都要往优先队列里面塞一个点,那就在塞的过程中,对这个点做一下标记就好了,想了一下午,才想出来,QAQ,感觉就跟DP差不多的原理,真的很菜,直接把kuangbin版 Dijkstra+堆优化改一改就好了,太菜了
AC_code:
/*
* 使用优先队列优化 Dijkstra 算法
* 复杂度 O(ElogE)
* 注意对 vector<Edge>E[MAXN] 进行初始化后加边
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll INF=1000000005LL;
const int MAXN=1005;
struct qnode {
int v;
ll c;
int flag;// 1表示已经使用了技能卡 0表示没有
qnode(int _v=0,ll _c=0,int _flag=0):v(_v),c(_c),flag(_flag) {}
bool operator <(const qnode &r)const {
return c>r.c;
}
};
struct Edge {
int v;
ll cost;
Edge(int _v=0,ll _cost=0):v(_v),cost(_cost) {}
};
vector<Edge>E[MAXN];
bool vis[2][MAXN];// 1表示已经使用了技能卡 0表示没有
ll dist[2][MAXN];// 1表示已经使用了技能卡 0表示没有
//点的编号从 1 开始
void Dijkstra(int n,int start) {
memset(vis,false,sizeof(vis));
for(int i=1; i<=n; i++)dist[0][i]=dist[1][i]=INF;
priority_queue<qnode>que;
while(!que.empty())que.pop();
dist[0][start]=dist[1][start]=0;
que.push(qnode(start,0,0));
qnode tmp;
while(!que.empty()) {
tmp=que.top();
que.pop();
int u=tmp.v;
int flag=tmp.flag;
if(vis[flag][u])continue;
vis[flag][u]=true;
int len=E[u].size();
for(int i=0; i<len; i++) {
int v=E[u][i].v;
ll cost=E[u][i].cost;
if(!vis[flag][v]&&dist[flag][v]>dist[flag][u]+cost) {
dist[flag][v]=dist[flag][u]+cost;
que.push(qnode(v,dist[flag][v], flag));
}
if(!vis[1][v]&&dist[1][v]>dist[0][u]+cost/2&&!flag) {
dist[1][v]=dist[0][u]+cost/2;
que.push(qnode(v,dist[1][v], 1));
}
}
}
}
void addedge(int u,int v,ll w) {
E[u].push_back(Edge(v,w));
}
int main() {
int t, cas = 1;
scanf("%d", &t);
while(t--) {
printf("Case #%d:\n",cas++);
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
E[i].clear();
}
ll ans = 0;
int a, b;
ll c;
while(m--) {
scanf("%d %d %lld", &a, &b, &c);
addedge(a, b, c);
}
int x, y;
scanf("%d %d", &x, &y);
Dijkstra(n, x);
ans = min(dist[0][y],dist[1][y]);
if(ans == INF) {
printf("-1\n");
} else
printf("%lld\n", ans);
}
return 0;
}