Codechef GALACTIK solution - algorithm

Here's the link for the problem:
I have used union-find algorithm to solve the problem.
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
#define INT 100000000
unordered_map<ll, ll> parent;
unordered_map<ll, ll> depth;
std::vector<ll> cost;
ll find_set(ll x) {
if (x == parent[x])return x;
parent[x] = find_set(parent[x]);
return parent[x];
}
void union_set(ll x, ll y) {
/*
Creating a disjoint set such that the node with smallest cost
being the root using union-rank concept.
*/
ll rep1 = find_set(x), rep2 = find_set(y);
if (depth[rep1] > depth[rep2])parent[rep1] = rep2;
else if (depth[rep2] >= depth[rep1])parent[rep2] = rep1;
}
int main() {
ll n, m;
cin >> n >> m;
ll c[m + 1][3];
for (ll i = 1; i <= m; i++) {
cin >> c[i][1] >> c[i][2]; //Accepting the edges
}
for (ll i = 1; i <= n; i++) {
parent[i] = i;
cin >> depth[i];
if (depth[i] < 0)depth[i] = INT;
/*we assume that each negative cost is replaced by a very
large positive cost.*/
}
for (ll i = 1; i <= m; i++) {
union_set(c[i][1], c[i][2]);
}
set<ll> s;
std::vector<ll> v;
//storing representatives of each connected component
for (auto i = 1; i <= n; i++)s.insert(depth[find_set(i)]);
for (auto it = s.begin(); it != s.end(); it++)v.push_back(*it);
sort(v.begin(), v.end());
if (s.size() == 1) {
//Graph is connected if there is only 1 connected comp
cout << 0 << endl;
return 0;
}
bool flag = false;
ll p = 0;
for (ll i = 1; i < v.size(); i++) {
if (v[i] == INT) {
flag = true;
break;
}
p += (v[0]+v[i]);
}
if (flag)cout << -1 << endl;
else cout << p << endl;
return 0;
}
Logic used in my program:
To find the answer, take the minimum value of all the valid values in a connected component.Now to make the graph connected, Take the minimum value of all the values we got from the above step and make edge from that node to all the remaining nodes.If graph is already connected than answer is 0.if there exists a connected component where all nodes are not valid to be chosen, than answer is not possible (-1).
But this solution is not accepted?What's wrong with it?

Related

Djikstra's Algorithm in C++

I am writing Djikstra's algorithm in C++, and am having trouble getting the code to print anything other than the path from A->A. I need to get it to find the path from A->X where X is any one of the nodes A-I.
Expected Output
Actual Output
#include <climits>
#include <fstream>
#include <iostream>
using namespace std;
const int V = 9;
// Function to print shortest path from source to j
// using parent array
void printPath(int parent[], int j) {
char str = j;
// Base Case : If j is source
if (parent[j] == -1) {
cout << str << " ";
return;
}
printPath(parent, parent[j]);
// printf("%d ", j);
cout << str << " ";
}
int miniDist(int distance[], bool Tset[]) // finding minimum distance
{
int minimum = INT_MAX, ind;
for (int k = 0; k < V; k++) {
if (Tset[k] == false && distance[k] <= minimum) {
minimum = distance[k];
ind = k;
}
}
return ind;
}
void DijkstraAlgo(int graph[V][V], char sourceNode,
char endNode) // adjacency matrix
{
int distance[V]; // array to calculate the minimum distance for each node
bool Tset[V]; // boolean array to mark visited and unvisited for each node
int parent[V]; // Parent array to store shortest path tree
// Value of parent[v] for a vertex v stores parent vertex of v
// in shortest path tree.
for (int k = 0; k < V; k++) {
distance[k] = INT_MAX;
Tset[k] = false;
}
parent[sourceNode] = -1; // Parent of root (or source vertex) is -1.
distance[sourceNode] = 0; // Source vertex distance is set 0
for (int k = 0; k < V; k++) {
int end = miniDist(distance, Tset);
Tset[end] = true;
for (int k = 0; k < V; k++) {
// updating the distance of neighbouring vertex
if (!Tset[k] && graph[end][k] && distance[end] != INT_MAX &&
distance[end] + graph[end][k] < distance[k]) {
distance[k] = distance[end] + graph[end][k];
parent[k] = end;
}
}
}
cout << "Vertex\t\tDistance from source vertex\t\t Path" << endl;
int k = sourceNode;
char str = k;
// cout<<str<<"\t\t\t"<<distance[k]<<endl;
cout << str << "\t\t\t" << distance[k] << "\t\t\t\t\t\t\t\t";
printPath(parent, k);
cout << endl;
}
int main() {
char choice1, choice2;
ifstream inFile;
inFile.open("graph.txt");
int graph[V][V];
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++)
inFile >> graph[i][j];
}
cout << "Nodes: "
<< "A, B, C, D, E, F, G, H, I" << endl;
cout << "Enter starting node: ";
cin >> choice1;
cout << "Enter ending node: ";
cin >> choice2;
cout << endl;
DijkstraAlgo(graph, choice1, choice2);
inFile.close();
return 0;
}
So, I have to be able to pass the endNode parameter to something somehow, correct?
The main issue lies here:
int miniDist(int distance[], bool Tset[])
In your minimum distance calculation, you don't exclude the source vertex. All other vertices have INT_MAX distance and the source has 0 distance, so it gets picked. Try going through the algorithm once again to fix your implementation.

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

Stuck with DFS/BFS task (USACO silver)

competitive programming noob here. I've been trying to solve this question:
http://www.usaco.org/index.php?page=viewproblem2&cpid=646
The code I wrote only works with the first test case, and gives a Memory Limit Exceed error -- or ('!') for the rest of the test cases.
This is my code (accidently mixed up M and N):
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
using std::vector;
vector<int> check;
vector< vector<int> > A;
void dfs(int node)
{
check[node] = 1;
int siz = A[node].size();
for (int i = 0; i < siz; i++)
{
int y = A[node][i];
if (check[y] == 0)
{
dfs(y);
}
}
}
bool connected(vector<int> C)
{
for (int i = 1; i <= C.size() - 1; i++)
{
if (C[i] == 0)
{
return false;
}
}
return true;
}
int main()
{
freopen("closing.in", "r", stdin);
freopen("closing.out", "w", stdout);
ios_base::sync_with_stdio(false);
int M, N;
cin >> M >> N;
check.resize(M + 1);
A.resize(M + 1);
for (int i = 0; i < N; i++)
{
int u, v;
cin >> u >> v;
A[u].push_back(v); A[v].push_back(u);
}
dfs(1);
if (!connected(check)) {
cout << "NO" << "\n";
}
else {
cout << "YES" << "\n";
}
fill(check.begin(), check.end(), 0);
for (int j = 1; j < M; j++)
{
int node;
bool con = true;
cin >> node;
check[node] = -1;
for (int x = 1; x <= N; x++)
{
if (check[x] == 0)
{
dfs(x);
break;
}
}
if (!connected(check)) {
cout << "NO" << "\n";
}
else {
cout << "YES" << "\n";
}
for (int g = 1; g <= M; g++)
{
if (check[g] == 1)
{
check[g] = 0;
}
}
}
return 0;
}
basically,
void dfs(int node) searches through the bidirectional graph starting from node until it reaches a dead end, and for each node that is visited, check[node] will become 1.
(if visited -> 1, not visited -> 0, turned off -> -1).
bool connected(vector C) will take the check vector and see if there are any nodes that weren't visited. if this function returns true, it means that the graph is connected, and false if otherwise.
In the main function,
1) I save the bidirectional graph given in the task as an Adjacency list.
2) dfs through it first to see if the graph is initially connected (then print "Yes" or "NO") then reset check
3) from 1 to M, I take the input value of which barn would be closed, check[the input value] = -1, and dfs through it. After that, I reset the check vector, but keeping the -1 values so that those barns would be unavailable for the next loops of dfs.
I guess my algorithm makes sense, but why would this give an MLE, and how could I improve my solution? I really can't figure out why my code is giving MLEs.
Thanks so much!
Your DFS is taking huge load of stacks and thus causing MLE
Try to implement it with BFS which uses queue. Try to keep the queue as global rather than local.
Your approach will give you Time Limit Exceeded verdict. Try to solve it more efficiently. Say O(n).

How to find edges in route

Let's say I have a graph like this
I want to find all the edges from 1 to 3 i.e. 1 2... 2 4... 4 3. I can write the code for 1 to 5 quite easily but when the next node in descending order then my code doesn't work. Please help me with that.
Here is my code:-
given if there is edge between i and j then:-
arr[i][j]=0
where s is total number of nodes and i have to find edges between a and b
for(int i=a;i!=b;)
{
for(int j=1;j<=s;j++)
{
if(arr[i][j]==0)
{
//cout<<i<<" "<<j<<endl;
i=j;
}
}
}
This can be solved using Breadth first search algorithm we can keep track of the parent of the current node while performing a BFS, and then can construct the path from that if the path exists, i have written a c++ solution below
#include<iostream>
#include<queue>
using namespace std;
int n, arr[100][100], par[100], vis[100], ans[100];
void bfs(int start, int end){
queue<int> Q;
Q.push(start);
par[start] = -1;vis[start] = 1;
bool found = false;
while(Q.size() > 0){
int v = Q.front();
Q.pop();
if(v == end){
found = true;
break;
}
for(int i = 1;i <= n;i++){
if(arr[v][i] == 0 || vis[i] == 1) continue;
Q.push(i);vis[i] = 1;
par[i] = v;
}
}
if(found == false){
cout << "No Path Found" << endl;return;
}
int curr = end, len = 0;
while(curr != -1){
ans[len++] = curr;
curr = par[curr];
}
for(int i = len-1;i >= 1;i--) cout << ans[i] << " " << ans[i-1] << endl;
}
int main(){
n = 5;
arr[1][2] = 1;arr[2][1] = 1;
arr[2][4] = 1;arr[4][2] = 1;
arr[4][5] = 1;arr[5][4] = 1;
arr[3][4] = 1;arr[4][3] = 1;
bfs(1, 3);
return 0;
}
Link to solution on Ideone : http://ideone.com/X8QnNu

Resources