两个月前就搞这道题,昨天翻出来直接修改的当时的超时代码,经历了多种错误,最后终于还是AC了。
这道题还是挺好的一道题,需要正反两次BFS,需要加各种防超时的判断。实际上还是考差对问题的理解,什么时候应该剪枝,什么地方不必重复判断。
第一次反着BFS,找到各点到终点的最短距离。第二次正着BFS,顺着距离递减的方向,按照颜色小的优先的方法走。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <climits>
#include <queue>
#define MAXN 102400
using namespace std;
int n, m;
vector<int> road[MAXN], col[MAXN];
int d[MAXN], ans[MAXN];
bool vis[MAXN];
void clr()
{
for(int i = 0; i < MAXN; i++)
road[i].clear(), col[i].clear();
memset(d, -1, sizeof(d));
memset(ans, 0, sizeof(ans));
memset(vis, false, sizeof(vis));
}
void BFS1()
{
queue<int> qu;
qu.push(n);
d[n] = 0;
while(!qu.empty()){
int u = qu.front(); qu.pop();
for(size_t i = 0; i != road[u].size(); i++)
if(d[road[u][i]]==-1){
int v = road[u][i];
d[v] = d[u] + 1;
if(v == 1) return;
qu.push(v);
}
}
}
void BFS2()
{
queue<int> qu;
qu.push(1);
while(!qu.empty()){
int u = qu.front(); qu.pop();
if(u==n) return;
int curd = d[u];
int minclr = INT_MAX;
for(size_t i = 0, sz = road[u].size(); i < sz; ++i)
if(d[road[u][i]] + 1 == curd)
minclr = min(minclr, col[u][i]);
if(!ans[curd] || minclr<=ans[curd]) ans[curd] = minclr;
else continue;
for(size_t i = 0, sz = road[u].size(); i < sz; ++i){
int v = road[u][i];
if(!vis[v] && col[u][i]==minclr && d[v]+1==curd)
qu.push(v), vis[v] = true;
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
while(clr(), ~scanf("%d %d", &n, &m)){
while(m--){
int a, b, c; scanf("%d %d %d", &a, &b, &c);
road[a].push_back(b); col[a].push_back(c);
road[b].push_back(a); col[b].push_back(c);
}
BFS1(); BFS2();
printf("%d\n", d[1]);
for(int i = d[1]; i >= 1; --i){
if(i==d[1]) printf("%d", ans[i]);
else printf(" %d", ans[i]);
}
printf("\n");
}
return 0;
}