題目
G題 Lexicographically Minimum Walk
題解
思路
要求s到t的字典序最小的路徑,有可能不可達或路徑無限長。
我們的貪心策略:要讓字典序最小,那每次我們都要選取所相連的字典序最小的那條邊,這樣字典序能夠做到最小,但是這樣有可能走進死衚衕裏去了,而實際上s和t是可達的。
那麼我們進行一個預處理,我們想要知道走哪些路是能到達t的,得出這些路之後,我們在這些路上進行上述的貪心策略即爲答案。
怎麼求s到t的可達路呢?
將原圖反建,以t爲起點跑一個dfs即可。這樣被標記上的點都是可達t的,我們只在這些點上進行貪心策略,即可求出答案。
代碼
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <queue>
using namespace std;
#define MP(a, b) make_pair(a, b)
typedef pair <int, int> P;
const int maxn = 1e5 + 10;
int n, m, s, t;
vector <P> G[maxn];
vector <int> rev_G[maxn];
bool rev_vis[maxn];
bool G_vis[maxn];
vector <int> ans;
void dfs_rev(int u){
rev_vis[u] = true;
for(int i = 0; i < rev_G[u].size(); i++)
if(!rev_vis[rev_G[u][i]])
dfs_rev(rev_G[u][i]);
}
void dfs(int u){
if(u == t){
for(int i = 0; i < ans.size(); i++){
printf("%d ", ans[i]);
}
exit(0);
}
if(G_vis[u]){
printf("TOO LONG\n");
exit(0);
}
G_vis[u] = true;
for(int i = 0; i < G[u].size(); i++){
if(rev_vis[G[u][i].first]){
ans.push_back(G[u][i].second);
dfs(G[u][i].first);
}
}
}
bool cmp(P a, P b){
return a.second < b.second;
}
int main(){
cin >> n >> m >> s >> t;
int u, v, c;
for(int i = 1; i <= m; i++){
scanf("%d %d %d", &u, &v, &c);
G[u].push_back(MP(v, c));
rev_G[v].push_back(u);
}
for(int i = 1; i <= n; i++){
sort(G[i].begin() , G[i].end(), cmp);
}
dfs_rev(t);//check rev_G
if(!rev_vis[s]){
return 0 * printf("IMPOSSIBLE\n");
}
dfs(s);//dfs G
return 0;
}