Why do I keep getting TLE for POJ 1984 -- Navigation Nightmare? - algorithm

#include <iostream>
#include <vector>
#include <cassert>
#include <queue>
using namespace std;
struct vectors{
int x;
int y;
bool visited;
vectors(int x = 0, int y = 0){
this -> x = x;
this -> y = y;
visited = false;
}
bool isNotFound(){
return visited == false;
}
void setZero(){
x = 0;
y = 0;
}
vectors operator+(vectors others){
return vectors(x + others.x, y + others.y);
}
vectors operator*(int others){
return vectors(x * others, y * others);
}
};
struct node{
int adjFarm;
int length;
char direction;
node(int f, int l, char d){
adjFarm = f;
length = l;
direction = d;
}
};
int num_villages;
char inverse_direction(char d){
assert(d == 'N' || d == 'E' || d == 'W' || d == 'S' );
switch(d){
case 'S': return 'N';
case 'N': return 'S';
case 'E': return 'W';
case 'W': return 'E';
}
}
void AddToPaths(int farm1, int farm2, char direction, int length, vector< vector<node> > &pathGraph){
pathGraph.at(farm1).push_back(node(farm2, length, direction));
pathGraph.at(farm2).push_back(node(farm1, length, inverse_direction(direction)));
}
vectors directionVector(int d){
switch(d){
case 'N': return vectors(0, 1);
case 'E': return vectors(1, 0);
case 'W': return vectors(- 1, 0);
case 'S': return vectors(0, - 1);
}
}
void print_coords(vector< vectors > coords){
for(int i = 1; i < num_villages + 1; i ++){
cout << "farm: " << i << " coordinates x at farm: " << coords.at(i).x << " coordinated y at farm: " << coords.at(i).y << endl;
}
}
void update(char direction, int newFarm, int length, int currentFarm, vector <vectors> &coords){
vectors directions = directionVector(direction);
coords.at(newFarm) = coords.at(currentFarm) + directions * length;
coords.at(newFarm).visited = true;
}
void computeCoords(vector <vectors> &coords, vector< vector<node> > &pathGraph){
queue <int> frontier;
frontier.push(1);
coords.at(1).visited = true;
while(!frontier.empty()){
int currentFarm = frontier.front();
frontier.pop();
for(int i = 0; i < pathGraph.at(currentFarm).size(); i ++){
node options = pathGraph.at(currentFarm).at(i);
if(coords.at(options.adjFarm).isNotFound()){
update(options.direction, options.adjFarm, options.length, currentFarm, coords);
frontier.push(options.adjFarm);
}
}
}
}
struct UnionFind{
vector<int> L;
UnionFind(int num_villages){
L.resize(num_villages + 1);
for(int i = 1; i <= num_villages; i ++){
L.at(i) = i;
}
}
int find(int x){
if(x == L.at(x)) return x;
int root = find(L.at(x));
L.at(x) = root;
return root;
}
int Union(int x, int y){
int root1 = find(x);
int root2 = find(y);
L.at(y) = root1;
}
};
int pos;
int query(int start, int destination, int order, UnionFind &reachables, vector<vectors> &coords, vector<vector<int> > &source_destination_order){
while(pos <= order){
reachables.Union(reachables.find(source_destination_order.at(pos).at(0)), reachables.find(source_destination_order.at(pos).at(1)));
pos ++;
}
if(reachables.find(start) == reachables.find(destination)){
return abs(coords.at(start).x - coords.at(destination).x) + abs(coords.at(start).y - coords.at(destination).y);
}
else{
return -1;
}
}
int main(void){
int num_roads;
cin >> num_villages;
cin >> num_roads;
vector <vector<node> > pathGraph(num_villages + 1);
vector <vectors > coords(num_villages + 1);
vector <vector <int> > source_destination_order(num_villages + 1, vector<int> (2));
//Adding inforamtion about the farms
int farm1;
int farm2;
char direction;
int length;
int source;
for(int i = 0; i < num_roads; i ++){
cin >> farm1;
cin >> farm2;
cin >> length;
cin >> direction;
AddToPaths(farm1, farm2, direction, length, pathGraph);
source_destination_order.at(i + 1).at(0) = farm1;
source_destination_order.at(i + 1).at(1) = farm2;
}
computeCoords(coords, pathGraph);
int numQueries;
cin >> numQueries;
int start;
int destination;
int order;
int result;
UnionFind reachables(num_villages);
pos = 1;
for(int i = 0; i < numQueries; i ++){
cin >> start;
cin >> destination;
cin >> order;
result = query(start, destination, order, reachables, coords, source_destination_order);
cout << result << endl;
}
}
I tried to create an undirected acyclic graph with the farms as the vertices and the roads as the edges, and then use BFS to compute the coordinates of each farm relative to the first farm. Afterwards I used the union find structure to create disjoint sets of farms that are reachable from each other at the time of the query. However, it seems like my code takes too long to run, how should I fix it?

Related

CSES Dynamic Range Minimum Queries

https://cses.fi/problemset/task/1649
I'm solving this problem using Segment Trees and the solution I've written is
#include <bits/stdc++.h>
#define MAX 1000000001
using namespace std;
int n;
vector<int> tree;
int sum(int a, int b)
{
a += n;
b += n;
int s = INT_MAX;
while(a <= b) {
if (a % 2 == 1) s = min(s, tree[a++]);
if (b % 2 == 0) s = min(s, tree[b--]);
a>>=1;
b>>=1;
}
return s;
}
void update(int k, int change)
{
k += n;
tree[k] = change;
for(int i = k>>1; i >= 1; i>>=1) {
tree[i] = min(tree[2*i], tree[2*i+1]);
}
return;
}
int main()
{
int q;
cin >> n >> q;
n = pow(2, ceil(log2(n)));
tree.resize(2*n, INT_MAX);
for(int i = 0; i < n; i++) {
cin >> tree[i+n];
}
for(int i = n-1; i >= 1; i--) {
tree[i] = min(tree[2*i], tree[2*i+1]);
}
int type, a, b;
for(int i = 0; i < q; i++) {
cin >> type >> a >> b;
if (type == 1) {
update(a-1, b);
} else {
cout << sum(a-1, b-1) << endl;
}
}
return 0;
}
It works with first test case, but not with the second one. I've looked at other solutions online and they all look similar to mine. Please, help me spot the mistake.

Special minimum spanning tree

There is a node that can only get one line, I use both kruskal and prim, but the judger said TLE(Time Limit Exceed).
Then I will describe the question. There are many computers, we need to connect all of them, we give the cost of connection between different computers, also we give the special number of computer which can be only connected by one line. Finally, we guarantee there is a answer and there is no Self-Loop, but there may have multiple edge which have different weight between same node.
Here is my kruskal code, it's TLE.
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct edge{
int start;
int end;
int weight;
}Edge;
int special = 0;
int edgenum;
Edge _edge[600005];
int i, j, k;
int counter = 0;
bool Cmp(const edge &a, const edge &b){
return a.weight < b.weight;
}
int getEnd(int vends[], int i){
while(vends[i] != 0)
i = vends[i];
return i;
}
void kruskal(){
int p1, p2, m, n, ans = 0;
int vends[10005] = {0};
sort(_edge, _edge+counter, Cmp);
for(i = 0; i < edgenum; ++i){
p1 = _edge[i].start;
p2 = _edge[i].end;
if ((p1 == k || p2 == k) && special)
continue;
m = getEnd(vends, p1);
n = getEnd(vends, p2);
if(m != n){
if (p1 == k || p2 == k)
special = 1;
vends[m] = n;
ans += _edge[i].weight;
}
}
cout << ans << endl;
}
int main(){
int n, m;
cin >> n >> m >> k;
edgenum = m;
while(m--){
int a, b, c;
cin >> a >> b >> c;
_edge[counter].start = a; //Get the Edge
_edge[counter].weight = c;
_edge[counter++].end = b;
// _edge[counter].start = b;
// _edge[counter].weight = c;
// _edge[counter++].end = a;
}
kruskal();
}
Here is my Prim, but also TLE:
#include <iostream>
using namespace std;
typedef char VertexType;
typedef struct node{
int adjvex = 0;
int weight = INT32_MAX;
struct node *next = NULL;
}Node;
typedef struct vnode{
VertexType data;
Node *firstnode = NULL;
}Vnode;
Vnode node[10005];
int VNUM;
int n, m, k;
int lowcost[10005] = {0};
int addvnew[10005]; //未加入最小生成树表示为-1,加入则为0
int adjecent[10005] = {0};
bool is_special = false;
int flag;
void prim(int start){
long long sumweight = 0;
int i, j;
Node *p = node[start].firstnode;
for (i = 1; i <= VNUM; ++i) { //重置
addvnew[i] = -1;
}
while (p->next != NULL){
if (lowcost[p->adjvex] == 0 || p->weight < lowcost[p->adjvex])
lowcost[p->adjvex] = p->weight;
p = p->next;
}
if (lowcost[p->adjvex] == 0 || p->weight < lowcost[p->adjvex])
lowcost[p->adjvex] = p->weight;
addvnew[start] = 0;
// adjecent[start] = start;
if (start == k) {
is_special = true;
flag = 1;
}
for (i = 1; i < VNUM; ++i) {
int min = INT32_MAX;
int v=-1;
for (j = 1; j <= VNUM; ++j) { //Find the min
if (addvnew[j] == -1 && lowcost[j] < min && lowcost[j] != 0){
min = lowcost[j];
v = j;
}
}
if (v != -1){ //if min is found
if (flag == 1){
for (int l = 0; l < 10005; ++l) {
lowcost[l] = 0;
}
flag = 0;
}
addvnew[v] = 0;
sumweight += min;
p = node[v].firstnode;
while(p->next != NULL){
if (is_special && p->adjvex == k){ //If find the special node
p = p->next;
continue;
}
if(addvnew[p->adjvex] == -1 && (lowcost[p->adjvex] == 0 || p->weight < lowcost[p->adjvex])){ //如果该点未连接
lowcost[p->adjvex] = p->weight;
}
p = p->next;
}
if (!(is_special && p->adjvex == k))
if(addvnew[p->adjvex] == -1 && (lowcost[p->adjvex] == 0 || p->weight < lowcost[p->adjvex])){
lowcost[p->adjvex] = p->weight;
}
}
}
cout << sumweight << endl;
}
int main(){
cin >> n >> m >> k;
VNUM = n;
while (m--){
int a, b, c;
cin >> a >> b >> c;
Node *p = (Node*)malloc(sizeof(Node));
p->adjvex = b;
p->weight = c;
p->next = node[a].firstnode;
node[a].firstnode = p;
Node *q = (Node*)malloc(sizeof(Node));
q->adjvex = a;
q->weight = c;
q->next = node[b].firstnode;
node[b].firstnode = q;
}
prim(k);
}
I don't know how to modify the both code, I try my best, thank you

Dijkstra running slow

There is a problem at Spoj called HIGHWAYS, that is basically to find the shortest path between 2 given cities.
The first time I solved it, I used Dijkstra algorithm... I got it right, although the code was kind of big, so I decided to redo it with smaller code (that obviously acts the same way), but it's getting Time Limit Exceeded.
I'd like to know what difference between them is making this TLE to happen.
The input is like this:
n //number of test cases
c e s e //number of cities (from 1 to c), number of edges, start and end cities
c1 c2 w //e lines, each with connection between c1 and c2 with weight w
Here are the long code (Accepted):
#include <bits/stdc++.h>
using namespace std;
#define si(n) scanf("%d", &n)
#define INF 99999
int d[100010];
struct edge {
int v, weight;
edge(int a, int w) {
v = a;
weight = w;
}
bool operator < (const edge & o) const {
return weight > o.weight;
}
};
struct vertex {
int value;
vector <edge> adj;
vertex() {
adj.clear();
}
vertex(int val) {
value = val;
adj.clear();
}
void add(edge a) {
adj.push_back(a);
}
};
struct graph {
vertex v[100010];
void add_v(int val) {
vertex a(val);
a.adj.clear();
v[val] = a;
}
void add_a(int v1, int v2, int p) {
v[v1].add(edge(v2, p));
v[v2].add(edge(v1, p));
}
void dijkstra(int n, int f) {
for(int i = 0; i <= f; i++ ) d[i] = INF;
priority_queue < edge > Q;
d[n] = 0;
int current;
Q.push(edge(n, 0));
while (!Q.empty()) {
current = Q.top().v;
Q.pop();
for (int i = 0; i < v[current].adj.size(); i++) {
edge a = v[current].adj[i];
if (d[a.v] > d[current] + a.weight) {
d[a.v] = d[current] + a.weight;
Q.push(edge(a.v, d[a.v]));
}
}
}
}
};
int main(){
int cases;
si(cases);
int v, a, ini, fim;
int v1, v2, w;
while(cases--){
si(v); si(a);
si(ini); si(fim);
graph g;
for(int i = 1; i <= v; i++){
g.add_v(i);
}
for(int i = 0; i < a; i++){
si(v1); si(v2); si(w);
g.add_a(v1, v2, w);
}
g.dijkstra(ini, v+1);
int dist = d[fim];
if(dist < 0 || dist >= INF) printf("NONE\n");
else printf("%d\n", dist);
}
}
Here is the short one (Time Limit Exceeded):
#include <bits/stdc++.h>
using namespace std;
struct edge{
int v, w;
edge(){}
edge(int a, int b){v = a; w = b;}
};
bool operator < (edge a, edge b) {return a.w < b.w;}
const int INF = INT_MAX;
typedef vector<vector<edge> > graph;
typedef priority_queue<edge> heap;
int d[100020];
void Dijkstra(graph G, int length, int s){
for(int i = 1; i <= length; i++) d[i] = INF;
edge base;
base.v = s;
base.w = d[s] = 0;
heap H;
H.push(base);
while(!H.empty()){
int current = H.top().v;
H.pop();
for (int i = 0; i < G[current].size(); i++) {
edge a = G[current][i];
if (d[a.v] > d[current] + a.w) {
d[a.v] = d[current] + a.w;
H.push(edge (a.v, d[a.v]));
}
}
}
}
int main(){
int cases;
int n, m, s, e;
int v1, v2, w;
scanf("%d", &cases);
while(cases--){
scanf("%d %d %d %d", &n, &m, &s, &e);
graph G(n + 1);
for(int i = 0; i < m; i++){
scanf("%d %d %d", &v1, &v2, &w);
G[v1].push_back(edge(v2, w));
G[v2].push_back(edge(v1, w));
}
Dijkstra(G, n, s);
if(d[e] != INF) printf("%d\n", d[e]);
else printf("NONE\n");
}
}
The difference is in how you control the priority queue. In the long version, you take the edges with a small weight first, which enables you to find the optimum earlier and cut many possible paths short:
bool operator < (const edge & o) const {
return weight > o.weight;
}
In the short version, you have the behaviour (accidentially?) reversed and always take the edge with the greatest weight, which means that you effectively probe all possible paths.
bool operator < (edge a, edge b) {return a.w < b.w;}
Change the inequality operator and both versions will run equally fast.
The containers of STL are slow. Avoid using vector if necessary.
here is my dij:
class graph
{
public :
int head[N],next[M],node[M];
int dist[M];
int tot;
void init()
{
tot = 0;
CLR(head,-1);
}
void add(int x,int y,int z = 1)
{
node[tot] = y;
dist[tot] = z;
next[tot] = head[x];
head[x] = tot++;
}
graph() {init();}
} g;
int dist[N]; ///the distance
///src means source. ter is optional, it means terminal
void dij(int src, graph &g, int ter=-1)
{
memset(dist,0x3f,sizeof(dist)); ///init d[i] as a very large value
dist[src] = 0;
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > pq;
pq.push(make_pair(dist[src],src));
while(!pq.empty())
{
int x = pq.top().second;
int d = pq.top().first;
if(d != dist[x])continue;
if(x == ter)return ;
for(int i = g.head[x] ; ~i ; i = g.next[i])
{
int y = g.node[i];
if(d+g.dist[i]<dist[y])
{
dist[y] = d + g.dist[i];
pq.push(make_pair(dist[y],y));
}
}
}
}

Unable to find a wrong answer testcase for spoj MMINPAID

Problem link : http://www.spoj.com/problems/MMINPAID/
Getting WA on submitting.
I have used bfs to reach Nth node and calculating minimum cost for nodes in a path using bitmask. However after running on a huge number of testcases and comparing with an accepted solution, not able to find a failure testcase.
Code:
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int MAXN = 15, INF = 1 << 29;
struct node {
int c, p, r;
};
struct node data[MAXN][MAXN];
vector<int> g[MAXN];
int N, M, dist[MAXN][1 << 11];
int bfs() {
for (int i = 0; i < MAXN; i++)
for (int k = 0; k < (1 << 11); k++)
dist[i][k] = INF;
queue< pair< pair <int, int> , int > > q;
int v = 1, path = (1 << 1), cost = 0;
dist[v][path] = 0;
q.push(make_pair(make_pair(v, path), cost));
while (!q.empty()) {
int curv = q.front().first.first;
int curpath = q.front().first.second;
int curcost = q.front().second;
q.pop();
for (int i = 0; i < g[curv].size(); i++) {
int nv = g[curv][i];
int d1 = curcost + data[curv][nv].r;
int d2 = INF;
if (curpath & (1 << data[curv][nv].c)) {
d2 = curcost + data[curv][nv].p;
}
int d3 = min(d1, d2);
int npath = curpath | (1 << nv);
if (d3 < dist[nv][npath]) {
dist[nv][npath] = d3;
q.push(make_pair(make_pair(nv, npath), d3));
}
}
}
int res = INF;
for (int i = 0; i < (1 << 11); i++) {
res = min(res, dist[N][i]);
}
return res;
}
int main() {
scanf("%d %d", &N, &M);
for (int i = 0; i < M; i++) {
int a, b, c, p, r;
scanf("%d %d %d %d %d", &a, &b, &c, &p, &r);
g[a].push_back(b);
data[a][b] = (struct node) {c, p, r};
}
int ret = bfs();
if (ret == INF) printf("impossible\n");
else printf("%d\n", ret);
return 0;
}
I think the problem might be that your data[a][b] structure assumes there is at most a single road from a to b.
However, the problem states:
There may be more than one road connecting one city with another.

Finding bridges in graph without recursion

I have this code to find bridges in a connected graph:
void dfs (int v, int p = -1) {
used[v] = true;
tin[v] = fup[v] = timer++;
for (size_t i=0; i<g[v].size(); ++i) {
int to = g[v][i];
if (to == p) continue;
if (used[to])
fup[v] = min (fup[v], tin[to]);
else {
dfs (to, v);
fup[v] = min (fup[v], fup[to]);
if (fup[to] > tin[v])
printf("%d %d", v, to);
}
}
}
How to rewrite it without using recursion? I know, it's possible to do it and I should use stack, but this line must be executed after recursive call of dfs() and I can't achieve with a stack:
fup[v] = min(fup[v], fup[to])
So, how to rewrite my algorithm iteratively?
You want to make a "stack frame" structure
struct Frame {
Frame(int v, int p, int i, Label label);
int v;
int p;
int i;
};
// constructor here
and, as you say, a stack<Frame>. Between all of these fields, it's possible to simulate the call stack (untested code to give the general idea).
void dfs(int v, int p = -1) {
stack<Frame> st;
st.push(Frame(v, p, 0));
do {
Frame fr(st.top());
st.pop();
v = fr.v;
p = fr.p;
int i(fr.i);
if (i > 0) {
int to(g[v][i - 1]);
fup[v] = min(fup[v], fup[to]);
if (fup[to] > tin[v]) { printf("%d %d", v, to); }
if (i == g[v].size()) { continue; }
} else if (i == 0) {
used[v] = true;
tin[v] = fup[v] = timer++;
}
int to(g[v][i]);
if (to == p) { continue; }
if (used[to]) {
fup[v] = min(fup[v], tin[to]);
} else {
st.push(Frame(to, v, 0));
}
st.push(Frame(v, p, i + 1));
} while (!st.empty());
}
Sorry for the late reply.
Change code of previous answer and now it works fine.
Tested in contest task to find all bridges in connected Graph.
Hope it will help you.
// Copyright 2020 Kondratenko Evgeny
#include <iostream>
#include <vector>
#include <algorithm>
#include <stack>
struct Frame {
Frame(int v, int p, int i) : v(v), p(p), i(i) {
}
int v;
int p;
int i;
};
void DFS(int n,
const std::vector<std::vector<int>> &G,
const std::vector<std::vector<int>> &weights) {
std::vector<bool> used(n + 1, false);
std::vector<int> ret(n + 1); // the same as tup
std::vector<int> enter(n + 1); // the same as tin
std::stack<Frame> s;
s.push(Frame(1, -1, 0));
int time = 1;
while (!s.empty()) {
Frame f = s.top();
s.pop();
int v = f.v;
int p = f.p;
int i = f.i;
if (i == 0) {
enter[v] = ret[v] = time++;
used[v] = true;
}
// First part works befor DFS call
if (i < G[v].size()) {
int to = G[v][i];
s.push(Frame(v, p, i + 1));
if (to != p) {
if (used[to]) {
ret[v] = std::min(ret[v], enter[to]);
} else {
s.push(Frame(to, v, 0));
}
}
}
/*
Generally here is virtual DFS recursive call, which we are simulate now
*/
// Second part after DFS call
if (i > 0 && i <= G[v].size()) {
int to = G[v][i - 1];
if (to != p) {
ret[v] = std::min(ret[v], ret[to]);
if (ret[to] > enter[v]) {
std::cout << "bridge between: " << v << " and " << to;
std::cout << ", with weight: " << weights[v][i - 1] << std::endl;
}
}
}
}
}
int main() {
int n, m; // n - number of vertex, m - number of edges
std::cin >> n >> m;
std::vector<std::vector<int>> G(n + 1, std::vector<int>()); // your Graph
std::vector<std::vector<int>> weights(n + 1, std::vector<int>());
for (int i = 0; i < m; ++i) { // read edges with weigths
int u, v, w;
std::cin >> u >> v >> w;
G[u].push_back(v);
G[v].push_back(u);
weights[u].push_back(w);
weights[v].push_back(w);
}
DFS(n, G, weights);
return 0;
}

Resources