Ideal Path UVA - 1599

题目分析: 根据题目描述,给出的边可能会出现自环和两个节点之间有多条边的情况

我最初的想法是,在存储两条边的同时我先把他们记录下来,记录的同时比较两个节点之间颜色的最小值,只记录最小的然后我再把他们存到邻接表中,这样我就保证了两个节点之间只有一条边,之后我再开始dfs,在dfs的过程中,要注意剪枝来减少运算,
想到这些,我就去看紫书对这道题的说明,发现跟我想的不太一样,它选择了双向bfs,先从终点向前bfs求出每个节点到最终节点的最短路,然后再正向bfs,扩展的条件是每走一步路径要减一,这样保证了走的是最短路径,对于有相同颜色的路径,要把他们记录下来,然后再扩展。

明白了他的思路后我发现我不会写代码,只好去参考别人的代码,然后看了几篇博客后知道该怎么写了
他是用的数组表达链式结构,我个人比较喜欢指针表示,所以我就改成了指针

对于我最初的那个设想,感觉时间复杂度可能比较高
感觉可以dfs和bfs结合起来用,这样时间方面应该就符合要求了

唉,又快考试了,没时间研究了,看哪天有时间补上代码

#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>

using namespace std;
const int INF = 1e9 + 5;
const int MAXN = 1e6; 
struct Node              //图用邻接表存储
{
	int v, c;
	Node *next;
	Node(int V, int C) :v(V), c(C), next(NULL) {} 

};
Node *head[MAXN + 5];           //表头指针
bool vis[MAXN + 5];             
int d[MAXN + 5];                //记录每个节点到目标节点的距离
int n, m;
vector<int> vec;                 //正向bfs需要,记录相同颜色的节点
vector<int> color;              //存储答案
void bfs()//反向bfs
{
	memset(d, -1, sizeof(d));
	memset(vis, 0, sizeof(vis));
	queue<int> q;
	d[n] = 0; vis[n] = 1;
	q.push(n);
	while (!q.empty())
	{
		int u = q.front(); q.pop();
		if (u == 1) { cout << d[1] << endl; return; }
		Node *p = head[u];
		while (p != NULL) {
			if (!vis[p->v]) {
				d[p->v] = d[u] + 1;
				vis[p->v] = true;
				q.push(p->v);
			}
			p = p->next;
		}
	}
}
void bfs_sec()//正向bfs
{
	memset(vis, 0, sizeof(vis));
	queue<int> q;
	vis[1] = 1; q.push(1);
	int c = INF;
	while (!q.empty() || !vec.empty()) {
		if (q.empty()) {
			for (int i = 0; i < vec.size(); i++) {
				if (!vis[vec[i]]) {
					if (vec[i] == n) { color.push_back(c); return; }
					q.push(vec[i]);
					vis[vec[i]] = true;
				}
			}
			vec.clear();
			color.push_back(c);
			c = INF;
		}
		int u = q.front(); q.pop();
		Node *q = head[u];
		while (q != NULL) {
			if (d[u] - d[q->v] == 1 && q->c < c)
				c = q->c;
			q = q->next;
		}
		q = head[u];
		while (q != NULL) {
			if (d[u] - d[q->v] == 1 && q->c == c) vec.push_back(q->v);
			q = q->next;
		}

	}
}
void addedge(int u, int v, int c)    //添加边
{
	Node *p = new Node(v, c);
	p->next = head[u];
	head[u] = p;
}
void clear(Node *p)            //释放空间,虽然紫书上说过对于算法竞赛的题来说,内存一般不是问题                            
{							   //但养成一个好的习惯总是好的,这里用递归释放内存
	if (p->next != NULL) clear(p->next);
	delete p;
}
int main()
{
	ios_base::sync_with_stdio(false);
	while (cin >> n >> m) {
		for (int i = 1; i <= n; i++) head[i] = NULL;
		int u, v, c;
		while (m--)
		{
			cin >> u >> v >> c;
			if (u != v) {              //排除重边
				addedge(u, v, c);
				addedge(v, u, c);
			}
		}
		bfs();
		bfs_sec();
		for (int i = 0; i < color.size(); i++)//输出结果
			if (i) cout << ' ' << color[i];
			else cout << color[i];                  
			cout << endl;
			color.clear();
			vec.clear();
			for (int i = 1; i <= n; i++)
				if (head[i] != NULL) clear(head[i]);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_41776911/article/details/80901392
今日推荐