题目分析: 根据题目描述,给出的边可能会出现自环和两个节点之间有多条边的情况
我最初的想法是,在存储两条边的同时我先把他们记录下来,记录的同时比较两个节点之间颜色的最小值,只记录最小的然后我再把他们存到邻接表中,这样我就保证了两个节点之间只有一条边,之后我再开始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]);
}
}