I wanna go home( Djikstra 且特殊要求)

一、题意

    给一张图,图中每个节点都分别属于两个颜色,要求求出从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;
}


题目链接

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值