Recently, I was solving the Graphs section of the CSES problemset and encountered this problem. I used dijkstra algorithm to solve it.
I generally use the template from here, but in this question, this implementation gave me WA. When I used another implementation using visited array, it gave AC.
WA code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<vector<pair<ll,ll>>> adj,adj_rev;
vector<ll> d1,d2;
void dijkstra(){
set<pair<ll,ll>> st;
st.insert({0,1});
d1[1]=0;
while(!st.empty()){
ll node=st.begin()->second;
st.erase(st.begin());
for(auto it:adj[node]){
ll child=it.first,wt=it.second;
st.erase({d1[child],child});
if(d1[child]>d1[node]+wt){
d1[child]=d1[node]+wt;
st.insert({d1[child],child});
}
}
}
}
void dijkstra1(){
set<pair<ll,ll>> st;
ll n=adj.size()-1;
st.insert({0,n});
d2[n]=0;
while(!st.empty()){
ll node=st.begin()->second;
st.erase(st.begin());
for(auto it:adj_rev[node]){
ll child=it.first,wt=it.second;
st.erase({d2[child],child});
if(d2[child]>d2[node]+wt){
d2[child]=d2[node]+wt;
st.insert({d2[child],child});
}
}
}
}
int main(){
ll n,m;
cin>>n>>m;
adj=adj_rev=vector<vector<pair<ll,ll>>>(n+1);
d1=d2=vector<ll>(n+1,1e18);
while(m--){
ll a,b,c;
cin>>a>>b>>c;
adj[a].push_back({b,c});
adj_rev[b].push_back({a,c});
}
dijkstra();
dijkstra1();
ll ans=1e18;
for(int i=1;i<=n;i++){
for(auto it:adj[i]){
ans=min(ans,d1[i]+d2[it.first]+it.second/2);
}
}
cout<<ans;
return 0;
}
AC Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<vector<pair<ll,ll>>> adj,adj_rev;
vector<ll> d1,d2;
void dijkstra(){
set<pair<ll,ll>> st;
ll n=adj.size()-1;
vector<bool> vis(n+1,false);
st.insert({0,1});
d1[1]=0;
while(!st.empty()){
ll node=st.begin()->second;
st.erase(st.begin());
if(vis[node]) continue;
vis[node]=true;
for(auto it:adj[node]){
ll child=it.first,wt=it.second;
if(d1[child]>d1[node]+wt){
d1[child]=d1[node]+wt;
st.insert({d1[child],child});
}
}
}
}
void dijkstra1(){
set<pair<ll,ll>> st;
ll n=adj.size()-1;
vector<bool> vis(n+1,false);
st.insert({0,n});
d2[n]=0;
while(!st.empty()){
ll node=st.begin()->second;
st.erase(st.begin());
if(vis[node]) continue;
vis[node]=true;
for(auto it:adj_rev[node]){
ll child=it.first,wt=it.second;
if(d2[child]>d2[node]+wt){
d2[child]=d2[node]+wt;
st.insert({d2[child],child});
}
}
}
}
int main(){
ll n,m;
cin>>n>>m;
adj=adj_rev=vector<vector<pair<ll,ll>>>(n+1);
d1=d2=vector<ll>(n+1,1e18);
while(m--){
ll a,b,c;
cin>>a>>b>>c;
adj[a].push_back({b,c});
adj_rev[b].push_back({a,c});
}
dijkstra();
dijkstra1();
ll ans=1e18;
for(int i=1;i<=n;i++){
for(auto it:adj[i]){
ans=min(ans,d1[i]+d2[it.first]+it.second/2);
}
}
cout<<ans;
return 0;
}
Naturally, I adopted the visited array approach and discarded the one before.
Now, using the visited array approach on this, I encountered WA again.
WA Code
#include<bits/stdc++.h>
using namespace std;
void dijkstra(vector<int> adj[],vector<int> &dist,vector<int> &par){
set<pair<int,int>> st;
par[1]=dist[1]=0;
st.insert({0,1});
int n=dist.size()-1;
bool vis[n+1]={false};
while(!st.empty()){
auto itr=*st.rbegin();
int node=itr.second,d=itr.first;
st.erase(prev(st.end()));
if(vis[node]) continue;
vis[node]=true;
for(auto it:adj[node]){
if(d+1>dist[it]){
st.insert({d+1,it});
dist[it]=d+1;
par[it]=node;
}
}
}
}
void solve(){
int n,m;
cin>>n>>m;
vector<int> adj[n+1];
vector<int> dist(n+1,INT_MIN);
vector<int> par(n+1,-1);
while(m--){
int a,b;
cin>>a>>b;
adj[a].push_back(b);
}
dijkstra(adj,dist,par);
if(par[n]==-1){
cout<<"IMPOSSIBLE\n";
return;
}
vector<int> ans;
int x=n;
while(x){
ans.push_back(x);
x=par[x];
}
reverse(ans.begin(),ans.end());
cout<<ans.size()<<'\n';
for(auto it:ans) cout<<it<<' ';
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
solve();
return 0;
}
Now I am very confused about what template to use for dijkstra, being a newbie to graphs. I would highly appreciate if someone helps.
Even I had such confusing moments with Dijstra's Algorithm once. Could you please check and tell me whether the below implementation works? Even I would like to know whether it is accurate in all cases.
I would appreciate if you write the Dijkstra function taking adjacency list as input. Would be really easier to test it. Right now, it is a little difficult to read or use for me.
Nevertheless, if you want to test it yourself, create an account in cses.fi and submit your code (you would need to incorporate parent assigning as well).
There are a couple of things going on. Let's focus on the first problem you were solving, which seems to be Flight Discount.
Both of the dijkstra implementations are correct, but the first one contains a bug (and thus it gets WA). This bug is not present in the original implementation from CP-Algorithms.
In your function
dijkstra
(and also indijkstra1
)should have the top two lines swapped:
In the first (incorrect) piece of code, the node
child
may just get completely deleted from the set of possible next nodes without ever visiting it, which is obivously incorrect.But why did the implementation of dijkstra get WA in the second problem? I can assure you that the mistake is not in the implementation of dijkstra. You got WA, because dijkstra itself cannot solve that problem efficiently. Here is a test case where your code fails:
Due to the fact that pairs in c++ are sorted in order of first element and then second, and the second element of each pair is the node index, dijkstra will first go to node $$$4$$$ and to node $$$7$$$ from there, setting the parent of $$$7$$$ as $$$4$$$. After that, dijkstra will find the path $$$1 \rightarrow 3 \rightarrow 6 \rightarrow 7$$$ and because it is longer than $$$1 \rightarrow 4 \rightarrow 7$$$, the parent of $$$7$$$ gets set to $$$6$$$. Last, dijkstra will find the path $$$1 \rightarrow 2 \rightarrow 5 \rightarrow 4$$$ and set the parent of $$$4$$$ to $$$5$$$. But since $$$4$$$ got visited already, the algorithm doesn't update $$$7$$$'s parent back to $$$4$$$.
In order to make dijkstra work in this problem, you would have to visit every node again if the distance got updated, making the algorithm run in $$$O(m^2 \log n)$$$. This is the same reason as to why dijkstra doesn't work with negative weights.
Instead of dijkstra, this problem is meant to be solved with topological sorting and dp on DAG.
Thanks a lot for the clarification!