TLE in codeforces's Dijkstra - c++

I just learnt Dijkstra's algorithm and solved a few problems and I am trying to solve this http://codeforces.com/problemset/problem/20/C problem but I am getting Time limit Exceeded in a large test case, I want to know if my code can be further optimized in any way or if there is any other faster implementation of Dijkstra then let me know.
My code
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define vp vector<pii>
int p[100010],d[100010];
void printer(int current)
{
if(p[current]==-2)
{
printf("%d ",current);
return;
}
printer(p[current]);
printf("%d ",current);
}
class Prioritize
{
public:
int operator()(const pii &p1,const pii &p2)
{
return p1.second<p2.second;
}
};
int main()
{
priority_queue<pii, vp, Prioritize> Q;
int nv;
scanf("%d",&nv);
vp g[nv+1];
int ne,u,v,w;
scanf("%d",&ne);
for(int i=0;i<ne;i++)
{
scanf("%d %d %d",&u,&v,&w);
g[u].push_back(pii(v,w));
g[v].push_back(pii(u,w));
}
int source=1;
int size;
for(int i=1;i<=nv;i++)
{
d[i]=INT_MAX;
p[i]=-1;
}
d[source]=0;
p[source]=-2;//marker for source.
Q.push(pii(source,d[source]));
while(!Q.empty())
{
u=Q.top().first;
Q.pop();
size=g[u].size();
for(int i=0;i<size;i++)
{
v=g[u][i].first;
w=g[u][i].second;
if(d[v]>d[u]+w)
{
d[v]=d[u]+w;
p[v]=u;
Q.push(pii(v,d[v]));
}
}
}
/*for(int i=1;i<=nv;i++)
{
printf("Node %d and min weight = %d and parent = %d\n",i,d[i],p[i]);
}*/
if(p[nv]==-1)
{
printf("%d\n",-1);
return 0;
}
printer(nv);
return 0;
}

Your algorithm has complexity O(nm). I propose to add the following
Q.push(pii(source,d[source]));
while(!Q.empty())
{
u=Q.top().first;
int curD = Q.top().second; //this
if( curD > d[u]) continue; //and this
Q.pop();
size=g[u].size();
for(int i=0;i<size;i++)
{
After changes complexity will be O(mlogn). If you now russian you can read http://e-maxx.ru/algo/dijkstra_sparse

Related

How to traverse till a specified node in Weighted Undirected Graphs using BFS and DFS?

I have implemented the Weighted graph along with BFS and DFS. But I cannot figure a way out how to stop the traversal when a destination node (specified by user) is reached. Like user should enter the src and dest, and the BFS and DFS algorithm should print the tree until that specified node is reached. I have tried some things but I just cannot understand how to do this. I am attaching the code, any help would be appreciated.
#include "iostream"
#include "vector"
#include "queue"
#include "stack"
using namespace std;
typedef pair<int , int> Pair;
struct Edge{
int src, dest, weight;
};
class Graph{
public:
vector<vector<Pair>> adjacencyList;
Graph(vector<Edge> const &edges, int N)
{
adjacencyList.resize(N);
for(auto &edge: edges)
{
int src = edge.src;
int dest = edge.dest;
int weight = edge.weight;
adjacencyList[src].push_back(make_pair(dest,weight));
adjacencyList[dest].push_back(make_pair(src,weight));
}
}
};
void BFS(Graph const &graph, int src, vector<bool> &discovered)
{
queue<int> q;
discovered[src] = true;
q.push(src);
while(!q.empty())
{
src = q.front();
q.pop();
cout<<src<<" ";
for(int i = 0; i != graph.adjacencyList[src].size() ;i++)
{
if(!discovered[i])
{
discovered[i] = true;
q.push(i);
}
}
}
}
void DFS(Graph const &graph, int src, vector<bool> &discovered)
{
stack<int> stack;
stack.push(src);
while(!stack.empty()){
src = stack.top();
stack.pop();
if(discovered[src])
{
continue;
}
discovered[src] = true;
cout<<src<< " ";
for(int i = 0 ; i < graph.adjacencyList[src].size() ; i++)
{
if(!discovered[i])
{
stack.push(i);
}
}
}
}
void printGraph(Graph const &graph, int N)
{
for (int i = 0; i < N; ++i) {
for(Pair v: graph.adjacencyList[i])
{
cout<<"("<<i<<" , "<<v.first<<" , "<<v.second<<")";
}
cout<<endl;
}
}
int main()
{
vector<Edge> edges =
{
// `(x, y, w)` —> edge from `x` to `y` having weight `w`
{0,1}, {0,2}, {0,3},
{1, 2}, {2,4}, {3,3}, {4,4}
};
int N = 5;
Graph graph(edges,N);
// printGraph(graph,N);
vector<bool> discovered(N, false);
for(int i = 0; i<N; ++i)
{
if(!discovered[i])
{
BFS(graph, i, discovered);
}
}
cout<<endl;
vector<bool> discovered2(N, false);
for(int i = 0; i<N; i++)
{
if(!discovered2[i])
{
DFS(graph, i , discovered2);
}
}
cout<<endl;
printGraph(graph, N);
}
A recursive design makes this much simpler. here is the depth first version
// set stopNode global
......
bool cPathFinder::depthRecurse(int v)
{
// remember this node has been visted
visted[v] = true;
// is this the sop npde
if ( v == stopNode ) {
return true;
}
// look for new adjacent nodes
for (int w : myGraph.all_neighbors(v)) {
if (!visited[w])
{
// search from new node
if( depthRecurse(w) )
return true;
}
}
}

Exceeding time limit for bipartite graph problem

I am solving Bipartite graph problem on Coursera.
Actual problem statement is as follows:
I am using BFS to find if the given graph is bipartite or not but the grader is showing "time exceeded".
#include<bits/stdc++.h>
using namespace std;
int BFS(vector<vector<int>> &adList,int s,int n,set<int> &visited)
{
#define inf 0
vector<int> color(n+1,inf);
color[s]=-1;
visited.erase(s);
queue<int> Q;
Q.push(s);
while(!Q.empty())
{
int u=Q.front();
Q.pop();
for(int v:adList[u])
{
if(color[v]==inf)//if unvisited
{
visited.erase(v);
Q.push(v);
color[v]=color[u]*-1;
}
else
{
if((color[v]*color[u])>0)
return 0;
}
}
}
return 1;
}
int connectedComp(vector<vector<int>> &adList,int m,int n)
{
set<int> visited;
for(int i=1;i<=n;++i)
{
visited.insert(i);
}
int val;
while(!visited.empty())
{
int i=(*(visited.front()));
val=BFS(adList,i,n,visited);
if(!val)
return 0;
}
return 1;
}
int main()
{
int n,m;
cin>>n>>m;
vector<vector<int>> adList(n+1,vector<int>(0));
for(int i=1;i<=m;++i)
{
int s,d;
cin>>s>>d;
adList[s].push_back(d);
adList[d].push_back(s);
}
int val=connectedComp(adList,m,n);
cout<<val;
}
According to me complexity for this code should be O(|E|+|V|) but it still times out.
Failed case #17/27: time limit exceeded (Time used: 3.98/2.00, memory used: 42123264/536870912.)
I have gone through GFG but there also exists a same approach for this problem.

Find max cost edge between two nodes in tree

Task:
Given a weighted tree graph and a set of nodes pairs. For each pair (u,v) from set I need to find(effectively) maximum edge between (u,v).
My approach:
Using Tarjan's algoritm for each pair (u,v) we can find lowest common ancestor LCA(u,v) = a. Then we can present the path between (u,v) as union of (u,a) and (v,a) pathes and maximum edge between (u,v) as max(max_edge(u,a),max_edge(v,a)).
Problem:
I'm trying to add max_edge save in LCA algoritm, but haven't got any success yet.
The question is: How can I add support of max edge save at LCA Tarjan's algorithm?
My attempt code:
int max_cost;
int dsu_find(int node)
{
if (node == parent[node])
return node;
max_cost = std::max(max_cost, edges[node][parent[node]]);
return parent[node] = dsu_find(parent[node]);
}
void lca_dfs(int node, std::vector<std::list<int>> &query_list)
{
dsu_make(node);
ancestor[node] = node;
marks[node] = true;
for(auto neighbour:adjacency_list[node])
{
if (!marks[neighbour.first])
{
lca_dfs(neighbour.first,query_list);
dsu_unite(node, neighbour.first);
ancestor[dsu_find(node)] = node;
}
}
for (auto query_node : query_list[node])
if (marks[query_node])
{
dsu_find(query_node);
dsu_find(node);
printf("%d %d -> %lld\n", node, query_node,max_cost);
query_list[query_node].remove(node);
max_cost = 0;
}
}
But it's working incorrect.
My full lca implementation(without incorrect modifications):
std::vector<int> parent;
std::vector<int> rank;
std::vector<int> ancestor;
std::vector<bool> marks;
std::vector<std::list<std::pair<int, long long>>> adjacency_list;
void lca_dfs(int node, std::vector<std::list<int>> &query_list)
{
dsu_make(node);
ancestor[node] = node;
marks[node] = true;
for(auto neighbour:adjacency_list[node])
{
if (!marks[neighbour.first])
{
lca_dfs(neighbour.first,query_list);
dsu_unite(node, neighbour.first);
ancestor[dsu_find(node)] = node;
}
}
for (auto query_node : query_list[node])
if (marks[query_node])
{
printf("LCA of %d %d is %d\n", node, query_node,ancestor[dsu_find(query_node)]);
query_list[query_node].remove(node);
}
}
//dsu operations
void dsu_make(int node)
{
parent[node] = node;
rank[node] = 0;
}
int dsu_find(int node)
{
return node == parent[node] ? node : parent[node]=dsu_find(parent[node]);
}
void dsu_unite(int node_1,int node_2)
{
int root_1 = dsu_find(node_1), root_2 = dsu_find(node_2);
if(root_1!=root_2)
{
if(rank[root_1] < rank[root_2])
std::swap(root_1, root_2);
parent[root_2] = root_1;
if (rank[root_1] == rank[root_2])
rank[root_1]++;
}
}
*For each node query_list[node] consists of v such as (node,v) is needed pair.
I understood, that I using double memory(just for easier access).
I'll be gratefull for any hints or implementation fixes.
Hope this Implementation works for you.
#include <bits/stdc++.h>
#include <algorithm>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define ass 1e18
#define MOD 1000000007
#define mp make_pair
#define pb push_back
#define pf push_front
#define pob pop_back
#define pof pop_front
#define fi first
#define se second
#define sz(x) (ll)x.size()
#define present(c,x) ((c).find(x) != (c).end())
#define boost ios_base::sync_with_stdio(false);cin.tie(NULL);
#define debug(x) cout << #x << ": " << x << endl;
#define debug2(x,y) cout<<#x<<": "<< x<< ", "<< #y<< ": "<< y<< endl;
#define debug3(x,y,z) cout<<#x<<": "<< x<< ", "<< #y<< ": "<< y<<" "<<#z<<" : "<<z<< endl;
using namespace std;
typedef long long int ll;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define ordered_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
pair<int,int> parent[200005],par[200005],dpp[200005][19];
vector<pair< pair<int,int>,pair<int,int> > >v;
vector<pair<int,int> >vv[200005];
int level[200005],vis[200005];
ll ans[200005];
void dfs(int x,int p)
{
level[x]=level[p]+1;
for(int i=0;i<sz(vv[x]);i++)
{
if(vv[x][i].fi!=p)
{
par[vv[x][i].fi].fi=x;
par[vv[x][i].fi].se=vv[x][i].se;
dfs(vv[x][i].fi,x);
}
}
}
void computeparent(int n)
{
for(int i=1;i<=n;i++)
dpp[i][0]=par[i];
for(int j=1;j<=18;j++)
{
for(int i=1;i<=n;i++)
{
dpp[i][j].fi=dpp[dpp[i][j-1].fi][j-1].fi;
dpp[i][j].se=max(dpp[i][j-1].se,dpp[dpp[i][j-1].fi][j-1].se);
}
}
}
int lca(int a,int b)
{
if(level[b]>level[a])
swap(a,b);
int diff=level[a]-level[b];
int m=ceil(log2(diff));
for(int i=m;i>=0;i--)
{
if(diff&(1LL<<i))
a=dpp[a][i].fi;
}
if(a==b)
return a;
for(int i=m;i>=0;i--)
{
if(dpp[a][i].fi!=dpp[b][i].fi)
{
a=dpp[a][i].fi;
b=dpp[b][i].fi;
}
}
return dpp[a][0].fi;
}
int lca2(int a,int b)
{
int c=a,d=b;
if(level[b]>level[a])
swap(a,b);
int i,maxi=0,diff=level[a]-level[b];
int m=ceil(log2(diff));
for(int i=m;i>=0;i--)
{
if(diff&(1LL<<i))
{
maxi=max(maxi,dpp[a][i].se);
a=dpp[a][i].fi;
}
}
return maxi;
}
int finds(int a)
{
while(parent[a].fi!=a)
{
a=parent[a].fi;
}
return a;
}
void unions(int x,int y)
{
if(parent[x].se>parent[y].se)
parent[y].fi=x;
else if(parent[x].se<parent[y].se)
parent[x].fi=y;
else
{
parent[x].fi=y;
parent[x].se++;
}
}
void solve()
{
ll sum=0;
int n,m,i,a,b,c;
cin>>n>>m;
for(i=1;i<=n;i++)
{
parent[i].fi=i;
parent[i].se=0;
}
for(i=0;i<m;i++)
{
cin>>a>>b>>c;
v.pb(mp(mp(c,i),mp(a,b)));
}
sort(v.begin(),v.end());
for(i=0;i<sz(v);i++)
{
int a=v[i].se.fi,b=v[i].se.se;
int x=finds(a),y=finds(b);
if(x!=y)
{
vv[a].pb(mp(b,v[i].fi.fi));
vv[b].pb(mp(a,v[i].fi.fi));
ans[v[i].fi.se]=1;
unions(x,y);
sum+=v[i].fi.fi;
}
}
dfs(1,0);
computeparent(n);
for(i=0;i<m;i++)
{
if(ans[v[i].fi.se]==0)
{
int a=lca(v[i].se.fi,v[i].se.se);
ans[v[i].fi.se]=sum+v[i].fi.fi-max(lca2(a,v[i].se.fi),lca2(a,v[i].se.se));
}
else
ans[v[i].fi.se]=sum;
}
for(i=0;i<m;i++)
cout<<ans[i]<<"\n";
}
int main()
{
boost
int t=1;
//cin>>t;
while(t--)
{
solve();
}
return 0;
}

Wrong Answer http://www.spoj.com/problems/WORDS1/

I have written the following code for the above problem.
I have checked if Graph is connected by choosing the start node and doing DFS from it. And checking the conditions for Euler path and tour, in code that would be count= 2 or 0. It's working on all given test cases.But getting wrong answer on submission
#include<iostream>
#include<cmath>
#include<list>
#include<string>
#include<stack>
using namespace std;
class Graph
{
int V;
list<int> *adj;
int *in;
public:
Graph(int v)
{
this->V=v;
this->adj=new list<int>[V];
this->in=new int[V];
for(int i=0;i<V;i++)
{
in[i]=0;
}
}
void addEdge(int src,int des)
{
adj[src].push_back(des);
in[des]=in[des]+1;
}
void DFSUtil(bool visited[],int v)
{
stack<int> s;
s.push(v);
visited[v]=true; //mark v as visited;
while (!s.empty())
{
int top=s.top();
s.pop();
list<int> :: iterator it;
for(it=adj[top].begin();it!=adj[top].end();it++)
{
if(!visited[*it])
{
visited[*it]=true;
s.push(*it);
}
}
}
}
/*void DFSUtil(bool visited[],int v)
{
visited[v]=true;
list<int> :: iterator it;
for(it=adj[v].begin();it!=adj[v].end();it++)
{
if(!visited[*it])
{
DFSUtil(visited,*it);
}
}
}*/
// Graph reverseGraph()
// {
// Graph g(V);
// for(int i=0;i<V;i++)
// {
// list<int> :: iterator it;
// for(it=adj[i].begin();it!=adj[i].end();it++)
// {
// g.addEdge(*it,i);
// }
// }
// return g;
// }
bool isConnected()
{
//bool visited[V];
bool* visited=new bool[V];
for(int i=0;i<V;i++)
visited[i]=false;
int i=0;
int flag=0;
int n;
for(i=0;i<V;i++)
{
if(adj[i].size()>0)
{
n=i;
flag=1;
}
if(((int)adj[i].size()-in[i])==1 && in[i]==0) //selecting the start vertex i.e vertex with no incoming edges
{
n=i;
break;
}
}
if(i==V&&flag==0)
return 0;
DFSUtil(visited,n); //dfs to check if every node is reachable fro start vertex
for(int i=0;i<V;i++)
{
if(visited[i]==false && adj[i].size()>0)
return 0;
}
// Graph gr=reverseGraph();
// for(int i=0;i<V;i++)
// visited[i]=false;
// gr.DFSUtil(visited,n);
// for(int i=0;i<V;i++)
// {
// if(visited[i]==false && adj[i].size()>0)
// return 0;
// }
return 1;
}
bool isEuler()
{
int count=0;
int magnitude;
for(int i=0;i<V;i++) //check conditions on in and out edges, out edges=adj[].size
{
magnitude=in[i]-(int)adj[i].size();
if(magnitude<0)
magnitude=magnitude*-1;
if((magnitude)==1)
{
count=count+1;
}
else if(in[i]!=adj[i].size())
{
return 0;
}
}
if(count==1 || count>2)
return 0;
if(isConnected()==0) //check if graph is connected
return 0;
return 1;
}
};
int main()
{
int t;
//scanf("%d",&t);
cin>>t;
while(t--)
{
int n;
//scanf("%d",&n);
cin>>n;
string str;
if(n==1) //only one string entered
{
cin>>str;
cout<<"Ordering is possible.\n";
continue;
}
Graph g(26);
int src,des;
for(int i=0;i<n;i++)
{
cin>>str;
src=str[0]-'a';
des=str[str.length()-1]-'a';
g.addEdge(src,des);
}
if(g.isEuler())
{
cout<<"Ordering is possible.\n";
}
else
{
cout<<"The door cannot be opened.\n";
}
}
}
In your function isConnected, you attempt to find the start vertex with no incoming edges by breaking out of the for loop upon a certain condition. If this condition is not encountered, the loop variable i will contain the value 26, rather than an expected index in the range 0..25. When the value 26 is passed to the DFSUtil function it will caused an out of bounds array access. I get a crash on the line visited[v] = true;
A condition that will cause this to arise, is the test case from the linked site with the repeated word:
2
ok
ok
Your check to find the start vertex does not handle this case well.

uvaoj 208 how can i speed up my program

why my program Time Limited Error?
because of the sort?
this is the question
link text
#include <cstdio>
#include <cstring>
using namespace std;
int map[22][44];
int book[22];
int total;
int sum;
int way[22];
int tails[22];
int tail;
void init()
{
memset(map,0,sizeof(map));
memset(book,0,sizeof(book));
sum =0;
memset(way,0,sizeof(way));
way[1]=1;
memset(tails,0,sizeof(tails));
}
void sort()
{
int t;
for (int i=1;i<=22;i++)
{
if (tails[i]==0)
break;
else
{
for (int j=1;j<=tails[i]-1;j++)
for (int k=j+1;k<=tails[i];k++)
{
if (map[i][j] > map[i][k])
{
t = map[i][j];
map[i][j]=map[i][k];
map[i][k]=t;
}
}
}
}
}
void dfs(int x,int y)
{
if ((x < 1)||(x > 22))
return;
if (book[x]==1)
return;
//printf("%d \n",x);
if (x == total)
{
sum++;
for (int i=1;i<=y-1;i++)
{
printf("%d ",way[i]);
}
printf("%d",total);
printf("\n");
return;
}
tail = tails[x];
for (int i=1;i<=43;i++)
{
book[x]=1;
way[y]=x;
dfs(map[x][i],y+1);
book[x]=0;
}
}
int main()
{
int temp1,temp2;
//freopen("ex.in","r",stdin);
//freopen("ex.out","w",stdout);
int c = 0;
while(scanf("%d",&total)!=EOF)
{
c++;
printf("CASE ");
printf("%d",c);
printf(":");
printf("\n");
init();
for (;;)
{
scanf("%d%d",&temp1,&temp2);
if ((temp1 == 0)&&(temp2 == 0))
break;
else
{
tails[temp1]++;
tail = tails[temp1];
map[temp1][tail]=temp2;
tails[temp2]++;
tail = tails[temp2];
map[temp2][tail]=temp1;
}
}
sort();
dfs(1,1);
printf("There are ");printf("%d",sum);printf(" routes from the firestation to streetcorner ");printf("%d",total);printf(".");
printf("\n");
}
return 0;
}
Because your sorting algoritm is in worst-case O(n*n), you can use InnoSort for better worst-case complexity O(n*log(n)).
You are using C++ then use sort function from <algorithm> header to do this simplest.
Documentation you can find at http://www.sgi.com/tech/stl/sort.html
For a start, you're accessing tails and map past the end. C++ arrays are zero-indexed, so the first element is 0, and the last valid elements are tails[21] and map[21][43].