一、题意
给一张图,图中每个节点都分别属于两个颜色,要求求出从1号点到达2号点的最短路径,且该路径上最多只能有一条连接两个不同颜色的节点的边。
二、求解思路
因为题目中给出1号点和2号点的颜色一定是不同的,所以最短路径上一定至少有一条边是连接两个不同颜色的边,所以我们可以枚举这条边。具体求解方法就是先用Dijkstra算出从1号点出(且不经过任何异色点)到所有同色点的最短距离,同理求解2号点出发对所有同色点的最短距离,之后枚举特殊边(u, v), 该条路径的最小距离就是dist[1][u] + dist[2][v] + w(u, v)(假设u与1同色,v与2同色)。
三、代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 600 + 10;
const int maxm = 10000 + 10;
const int inf = 1 << 29;
struct edge{
int to;
int w;
int next;
}Edge[2 * maxm];
int head[maxn], color[maxn], n, m, pos;
int dist[3][maxn];
void init(){
for(int i = 0; i < maxn; i++) head[i] = -1;
pos = 0;
}
void addEdge(int u, int v, int w){
Edge[pos].to = v;
Edge[pos].w = w;
Edge[pos].next = head[u];
head[u] = pos;
pos++;
}
void Dijskra(int s){
for(int i = 0; i < maxn; i++) dist[s][i] = inf;
dist[s][s] = 0;
int V[maxn];
memset(V, 0, sizeof(V));
for(int i = 1; i <= n; i++){
int u = -1;
int minimum = inf;
for(int j = 1; j < n; j++){
if(color[j] == color[s] &&!V[j] && dist[s][j] < minimum){
minimum = dist[s][j];
u = j;
}
}
if(u == -1) return;
V[u] = 1;
for(int k = head[u]; k != -1; k = Edge[k].next){
int v = Edge[k].to;
if(!V[v]){
if(dist[s][u]+ Edge[k].w < dist[s][v]) dist[s][v] = dist[s][u] + Edge[k].w;
}
}
}
}
int main(){
//freopen("input.txt", "r", stdin);
while(scanf("%d", &n) != EOF){
if(!n) break;
init();
scanf("%d", &m);
for(int i = 1; i <= m; i++){
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
for(int i = 1; i <= n; i++) scanf("%d", &color[i]);
Dijskra(1);
Dijskra(2);
int ans = inf;
for(int i = 1; i <= n; i++){
for(int k = head[i]; k != -1; k = Edge[k].next){
int v = Edge[k].to;
if(color[i] != color[v]){
if(color[i] == 1){
if(dist[1][i] != inf && dist[2][v] != inf)
ans = min(ans, dist[1][i] + dist[2][v] + Edge[k].w);
// cout << dist[1][i] << " " << dist[2][v] << " " << Edge[k].w << endl;
}else{
if(dist[2][i] != inf && dist[1][v] != inf)
ans = min(ans, dist[2][i] + dist[1][v] + Edge[k].w);
// cout << dist[2][i] << " " << dist[2][v] << " " << Edge[k].w << endl;
}
}
}
}
if(ans == inf) printf("-1\n");
else printf("%d\n", ans);
}
return 0;
}