堆优化dijkstra

图有关的一道题目

叶哥和圈姐正在一个含有 N 个顶点和 M 条边的简单连通图里玩游戏。

圈姐首先要将图中的每一条边染成红色或者蓝色。

一条路径是一系列边,其中每对连续边都有一个共同的节点。如果一对连续边中的第一条边的颜色与第二条边的颜色不同,我们就称这为“颜色变化”。

在圈姐的染色工作结束后,叶哥就需要选择一条起点为 1,终点为 N 的路径。

叶哥可以选择图中的任意一条路径,但是叶哥要使这条路径中的“颜色变化”的次数最少。而圈姐则是要让叶哥选择的路径中发生的“颜色变化”的次数最多,不管叶哥怎么选。

现在请你求出,不管叶哥怎么选,都必须发生颜色变化的次数。

输入格式:

第一行为两个整数,分别为 N 和 M,其中 2≤N≤105,1≤M≤105。

接下来的 M 行分别为两个整数 ai 和 bi,意思是 ai 和 bi 中有一条无向边,其中 1≤ai,bi≤N,ai\=bi

简单图 (Simple graph):若一个图中没有自环和重边,它被称为简单图。具有至少两个顶点的简单无向图中一定存在度相同的结点。

输出格式:

输出一个整数,即不管叶哥怎么选,都必须发生颜色变化的次数。

输入样例:

在这里给出一组输入。例如:

7 8
1 2
1 3
2 4
3 4
4 5
4 6
5 7
6 7

输出样例:

在这里给出相应的输出。例如:

3

在这里插入图片描述

解释:1-7这条路上,1-2颜色未变,从2->4,颜色由红色变为蓝色,颜色改变次数+1,接着从4到6,颜色由蓝色变为红色,颜色改变次数+1,再从6到7,颜色改变次数+1,总共颜色改变为3次;

刚开始看到题目是一脸懵逼的,仔细看后结果这么简单!!!先说结论,从1出发,找到一条最短路到n,求1-n中间经过的节点数就可以了。

从1~任意结点k 的颜色变换次数 等于 中间经过的节点数

为什么?叶哥想让颜色变换最少,那个女的又可以任意改变边的颜色;初始假设边的颜色都是蓝色并且两人足够聪明,叶哥无论怎么走,颜色变换都是0,现在女的给边染上红色(女的足够聪明),叶哥仍然要使颜色变换最少,即走最短路即可。假设不是走的最短路,由上面的结论可知中间的节点数肯定不是最少的,反之,即求最短路(我们这里使用堆优化dijkstra)。

广搜也可以,这里给你们用堆优化dijkstra是为了学习高级一点的东西,广搜有点太基础了。

#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>

//堆优化dijkstra:每次找最近的点的时候不是用数组存起来的,而是用一个堆来存,这样每次找最近的点
//都是O(1)的复杂度,调整堆是O(logn)的复杂度
using namespace std;

const int N = 1e5+5;

int n, m;
typedef struct Node {
	int no, w;//no表示结点编号,w表示1-当前no的距离
    
    //重载小于号,满足w >= b.w 的就排在堆的下面
	bool operator < ( const Node &b ) const {
		return w >= b.w;
	}
}Vert;
//默认大根堆,我们要使用的是小根堆,所以上面重载了<
priority_queue<Vert> q;
//领接表
vector<int> chart[N];
int dis[N];
bool sign[N];

void dijkstra( int start )
{
	dis[start] = 0;
	Vert s = {start, 0};
	q.push(s);
	for ( int i = 1; i <= n; ++i )
	{
		if ( i != start ) {
			dis[i] = 0x3f3f3f3f;
		}
	}
//	for ( int i = 0; i < chart[start].size(); ++i ) {
//		dis[chart[start][i]] = 1;
//	}
//	cout << "size:" << q.size() << endl;
	while ( q.size() ) {
		Vert first = q.top();
		q.pop();
		int no = first.no;
//		cout << "no:" << no << endl;
		if ( !sign[no] ) {
			for ( int i = 0; i < chart[no].size(); ++i ) {
				if ( !sign[chart[no][i]] && dis[chart[no][i]] > dis[no] + 1 ) {
					dis[chart[no][i]] = dis[no] + 1;
					Vert v = {chart[no][i], dis[chart[no][i]]};
					q.push(v);
				}
			}
		}
		sign[no] = true;
	}
	
}

int main()
{
	cin >> n >> m;
	for ( int i = 0; i < m; ++i ) {
		int s, e;
		cin >> s >> e;
		chart[s].push_back(e);
		chart[e].push_back(s);
	}
	dijkstra(1);
	
//	for ( int i = 1; i <= n; ++i ) {
//		cout << dis[i] << ' ';
//	}
//	cout << endl;
	
	cout << dis[n]-1 << endl;
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值