Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
There are a lot of graph problems that require some modification of the BFS algorithm. I just come across this problem. I thought of this question with just an extension of the standard BFS algorithm.
The question states that:
We are given a country, having N cities and M bidirectional roads. Each city has a traffic light, showing only 2 colors i.e Green and Red. All the traffic lights switch their color from Green to Red or vice versa after every T seconds. We can cross a city only when the traffic light is green. Initially, all traffic light is green. In any city, if the traffic light is Red then we have to wait for its light to turn green. Time taken to travel any road is C. We have to find minimum time to reach City N from 1.
Note: graph doesn't contain a self-loop or multiple edges.
For example:
N=5,M=5,T=3,C=5
Edges are:
1 2,
1 3,
2 4,
1 4,
2 5.
Here minimum time to go from 1 to 5 is 11 through path 1 2 5.WE can reach city 2 in 5 secs. then wait for 1 second for the light to turn green and then 5 seconds to go to 5.
Can anyone share his approach toward this problem? whether it is a BFS problem or some other graph algorithm required too?
Better to unsderstand if psedoucode will be there along with algorithm?
Because all the cities start with same initial state, switch lights with the same frequency, and all the roads have the same duration, the traffic lights delay all routes equally.
As all roads have the same duration, this means that BFS will be an efficient way to solve the problem. The only adjustment to the standard algorithm is to adjust the time at each node to account for any delay due to the traffic lights.
(If the roads had different durations, or the lights switched irregularly, then a more advanced algorithm such as Dijkstra would be required.)
I'm assuming all edge weights have an integer number of seconds.
Note that the period of a traffic light is 2T. Take your original graph G and duplicate its nodes 2T times: G0, G1, ..., G2T - 1. If there is an edge in the original graph G from node a to b with weight w, then add an edge with weight w from each node a in Gt to b in G(t + w) mod 2T for each t where the light in a is green. Add an edge with weight 1 between each respective node in Gt, G(t+1) mod 2T, representing the possibility to wait at a city.
Finally, add one more copy of the nodes of G to your graph, D, that will be used for the destination nodes. Add an edge from each node in Gt to its respective node in D with weight 0.
Then the shortest path between nodes s in G0 and t in D follows exactly your problem.
#include <bits/stdc++.h>
using namespace std;
#define ll long long int
vector<int> g[1001];
vector<pair<ll,vector<ll>>> pt;
void dfs(ll st,ll e,ll vis[],vector<ll> rs,ll w){
rs.push_back(st);
if(st == e){
pt.push_back({w*(rs.size()-1),rs});
return;
}
for(auto u : g[st]){
if(vis[u] == 0){
vis[st] = 1;
dfs(u,e,vis,rs,w);
vis[st] = 0;
}
}
}
int main()
{
ll n,m,t,c,u,v;
cin>>n>>m>>t>>c;
while(m--){
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
if(n == 1)
cout<<0<<endl;
else if(n == 2)
cout<<t<<endl;
else{
vector<ll> rs;
ll w = c;
ll vis[n+1] = {0};
dfs(1,n,vis,rs,w);
if(pt.size() == 0)
cout<<-1<<endl;
else{
sort(pt.begin(),pt.end());
ll te = 0;
ll nt = 0;
for(int i=1;i<pt[0].second.size();i++){
te += c + (nt-te);
while(nt < te)
nt += t;
}
cout<<te<<endl;
}//else
}
return 0;
}
This Question was asked in a coding round of a company that i attended, I could come up with a BFS solution with O(n) Time Complexity.
(The coding round is over now. So here's my solution)-Edited
My Solution (Python 3):
def getPresentTrafficColorAndWaitTime(curr_color,traffic,cost_travel):
#color
val = (cost_travel//traffic)%2
if val == 1:
curr_color = 0 if curr_color==1 else 1
#waitTime
waitTime = traffic - (cost_travel%traffic)
return curr_color,waitTime
def bfs(adj,visited,curr,final,traffic,cost_travel):
queue = []
queue.append(1)
visited[1] = 1
dist = 0
# Red: 1 , Green: 0
curr_color = 0
temp_cost_travel = cost_travel
while queue:
length = len(queue)
for _ in range(length):
curr = queue[0]
queue.pop(0)
for i in adj[curr]:
if i == final:
return dist+cost_travel
elif visited[i] == 0:
visited[i] = 1
queue.append(i)
curr_color,waitTime = getPresentTrafficColorAndWaitTime(curr_color,traffic,temp_cost_travel)
if curr_color == 1:
add_dist = waitTime
temp_cost_travel = cost_travel
curr_color = 0
else:
add_dist = 0
temp_cost_travel += cost_travel
dist += cost_travel + add_dist
return -1
# Taking Input and creating Adjacency-list using defaultdict
n,m,t,c = map(int,input().split())
adj_list = defaultdict(list)
for _ in range(m):
u,v = map(int,input().split())
adj_list[u] = adj_list.get(u,[]) + [v]
adj_list[v] = adj_list.get(v,[]) + [u]
visited = [0]*(n+1)
answer = bfs(adj_list,visited,1,n,t,c)
print(answer)
Related
A person is currently at (0,0) and wants to reach (X,0) and he has to jump a few steps to reach his house.From a point say (a,0), he can jump to either (a + k1,0) i.e forward of k1 steps or he can jump(a-k2,0) i.e backward jump of k2 steps. The first jump he takes must be forward.Also,he cannot jump backward twice consecutively.But he can jump any no of continuous forward jump.There are n points a1,a2 upto an where he cannot jump.
I have to determine minimum no of jumps to reach his house or to conclude that he cannot reach his house. If he can reach house print yes and specify no. of jumps If not print no.
Here
X = location of persons house.
N = no. of points where he cannot jump.
k1 = forward jump.
k2 = backward jump.
example
For inputs
X=6 N=2 k1=4 k2=2
Blocked points = 3 5
the answer is 3 (4 to 8 to 6 or 4 to 2 to 6)
For input
6 2 5 2
1 3
the person cannot reach his house
N can be upto 10^4 and X can be upto 10^5
I thought of using dynamic programming but i'm not able to implement it. Can anyone help?
I think your direction of using dynamic programming can work but I will show another way to solve the question with the same asymptotic time complexity as dynamic programming would achieve.
This question can be described as a problem in graphs where you have X nodes indexed 1 to X and these is an edge between every a and a + k1, b and b - k2, where you remove the nodes in N.
This will be enough if you can jump backward how many times you would like but you cannot jump twice in a row so you can add the following modification: Duplicate the graph's nodes, duplicate also the forward going edges but make them go from the duplicated to the original, now make all of the backward going edges to go to the duplicated graph. Now every backward edge will send you to the duplicated and you will not be able to take a backward edge again until you will go to the original using a forward going edge. This will make sure that after a backward edge you will always take a forward edge - so you will not be able to jump forward twice.
Now finding the shortest path from 1 to X is like finding smallest number of jumps since edge is a jump.
Finding the shortest path in directed unweighted graph takes O(|V|+|E|) time and memory (using BFS), your graph has 2 * X as |V| and also the number of edges will be 2 * 2 * X so time and memory complexity of O(X).
If you can jump backward twice you use the networkx library in python for a simple demo (you can also use if for complicated demo):
import matplotlib.pyplot as plt
import networkx as nx
X = 6
N = 2
k1 = 4
k2 = 2
nodes = [0, 1, 2, 4, 6]
G = nx.DiGraph()
G.add_nodes_from(nodes)
for n in nodes:
if n + k1 in nodes:
G.add_edge(n, n + k1)
if n - k2 in nodes:
G.add_edge(n, n - k2)
nx.draw(G, with_labels=True, font_weight='bold')
plt.plot()
plt.show()
path = nx.shortest_path(G, 0, X)
print(f"Number of jumps: {len(path) - 1}. path: {str(path)}")
Would a breadth-first search be efficient enough?
Something like this? (Python code)
from collections import deque
def f(x, k1, k2, blocked):
queue = deque([(k1, 0, None, None)])
while (queue):
(p, depth, direction, prev) = queue.popleft()
if p in blocked or (x + k2 < p < x - k1): # not sure about these boundaries ... ideas welcome
continue
if p == x:
return depth
blocked.add(p) # visited
queue.append((p + k1, depth + 1, "left", direction))
if prev != "right":
queue.append((p - k2, depth + 1, "right", direction))
X = 6
k1 = 4
k2 = 2
blocked = set([3, 5])
print f(X, k1, k2, blocked)
X = 2
k1 = 3
k2 = 4
blocked = set()
print f(X, k1, k2, blocked)
Here is the code of גלעדברקן in c++:
#include <iostream>
#include <queue>
using namespace std;
struct node {
int id;
int depth;
int direction; // 1 is left, 0 is right
};
int BFS(int start, int end, int k1, int k2, bool blocked[], int length)
{
queue<node> q;
blocked[0] = true;
q.push({start, 0, 0});
while(!q.empty())
{
node f = q.front();
q.pop();
if (f.id == end) {
return f.depth;
}
if(f.id + k1 < length and !blocked[f.id + k1])
{
blocked[f.id + k1] = true;
q.push({f.id + k1, f.depth + 1, 0});
}
if (f.direction != 1) { // If you just went left - don't go left again
if(f.id - k2 >= 0 and !blocked[f.id - k2])
{
blocked[f.id - k2] = true;
q.push({f.id - k2, f.depth + 1, 1});
}
}
}
return -1;
}
int main() {
bool blocked[] = {false, false, false, false, false, false, false};
std::cout << BFS(0, 6, 4, 2, blocked, 7) << std::endl;
return 0;
}
You can control on the length of the steps, the start and end, and the blocked nodes.
I'm trying to solve this problem, O(N^2) solution is simple, O(N) is possible, but I cannot think of how. Here's the question:
There are N cities and N directed roads in Steven's world. The cities are numbered from 0 to N - 1. Steven can travel from city i to city (i + 1) % N, ( 0-> 1 -> 2 -> .... -> N - 1 -> 0).
Steven wants to travel around the world by car. The capacity of his car's fuel tank is C gallons. There are a[i] gallons he can use at the beginning of city i and the car takes b[i] gallons to travel from city i to (i + 1) % N.
How many cities can Steven start his car from so that he can travel around the world and reach the same city he started?
Note
The fuel tank is initially empty.
Input Format
The first line contains two integers (separated by a space): city number N and capacity C.
The second line contains N space-separated integers: a[0], a[1], … , a[N - 1].
The third line contains N space-separated integers: b[0], b[1], … , b[N - 1].
Output Format
The number of cities which can be chosen as the start city.
Sample Input
3 3
3 1 2
2 2 2
Sample Output
2
Explanation
Steven starts from city 0, fills his car with 3 gallons of fuel, and use 2 gallons of fuel to travel to city 1. His fuel tank now has 1 gallon of fuel.
On refueling 1 gallon of fuel at city 1, he then travels to city 2 by using 2 gallons of fuel. His fuel tank is now empty.
On refueling 2 gallon of fuel at city 2, he then travels back to city 0 by using 2 gallons of fuel.
Here is the second possible solution.
Steven starts from city 2, fill his car with 2 gallons, and travels to city 0.
On refueling 3 gallons of fuel from city 0, he then travels to city 1, and exhausts 2 gallons of fuel. His fuel tank contains 1 gallon of fuel now. He can then refuel 1 gallon of fuel at City 1, and increase his car's fuel to 2 gallons and travel to city 2.
However, Steven cannot start from city 1, because he is given only 1 gallon of fuel, but travelling to city 2 requires 2 gallons.
Hence the answer 2.
Now I know this algorithm could be solved in O(N) time complexity, which I am unable to, guess it can be solved using dynamic programming, please help me get a clue how it could be broken into sub problems.
I've made and an algorithm that should solve the problem, it outputs 2 for your case, but it must be tested on other testcases.
I'm not sure it's correct. My main idea was that if you can make an iteration starting from one point you can make how many you wish, and the reverse is also true. If you can't make more than one, you cannot make even one.
#include <algorithm>
#include <iostream>
using namespace std;
#define PROB_SIZE 3
int n = PROB_SIZE, c = 3;
int a[PROB_SIZE] = {3, 1, 2}; // available
int b[PROB_SIZE] = {2, 2, 2}; // used
int d[PROB_SIZE];
int dmin[PROB_SIZE];
int main()
{
//The fuel used in the trip to next node (amount put in minus the amount consumed in one trip).
for (int i = 0; i < n; i++) {
d[i] = a[i] - b[i];
}
//The fuel that i need to start a trip in this point and reach point 0.
dmin[n - 1] = d[n - 1];
for (int i = n - 2; i >= 0; i--) {
dmin[i] = min(d[i], d[i] + dmin[i + 1]);
}
//The second loop to be sure i cover a whole loop from any point.
dmin[n - 1] = min(d[n - 1], d[n - 1] + dmin[0]);
for (int i = n - 2; i >= 0; i--) {
dmin[i] = min(d[i], d[i] + dmin[i + 1]);
}
//If for any point i need to have more fuel than i can carry then the trip is impossible for all points.
for (int i = 0; i < n; i++) {
if ((-dmin[i] + a[i]) > c) {
cout << 0 << endl;
return 0;
}
}
int cnt = 0;
//Any point that i need to have 0 fuel to reach point 0 making at least one round trip is a good starting point.
for (int i = 0; i < n; i++) {
if (dmin[i] >= 0) {
cnt++;
}
}
cout << cnt << endl;
}
First, I would like to point out that this question is word-for-word lifted from an exercise on HackerRank.
Here's a sketch of an algorithm that has been confirmed to pass all test cases on that site for this particular problem in O(N) time.
For all partial "trips" starting from 0 and ending at i for 0 < i < N, compute the following information:
What is the minimal gas we need to begin the trip at city 0 in order to successfully go from 0 to i?
Starting with this minimal amount (assuming the partial trip is even possible) how much gas will we have as we enter city i?
During such a trip, what is the largest amount of gas you will ever carry in your tank?
The reason we need #3 is because of the limited gas tank capacity sometimes prevents us from taking the "gas profile" of some trip and just "shifting everything up". Knowing how close we are to the ceiling for some given trip tells us exactly how much we can "shift up" before we hit the ceiling. (This sounds vague, but one should think about this point closely).
Once you have these three for every 0 < i < N, you also must compute these three for all partial trips starting at some i with 0 < i < N and wrapping around back to zero.
All six of these figures of merit can be computed in O(1) time per city using some slightly clever dynamic programming, and once you have them all for all the cities, it takes O(1) time to check if a city can wrap around completely.
Here is the python implementation of above idea:
def travelAroundTheWorld(a, b, c):
a = [min(i,c) for i in a]
if max(b) > c:
return 0
min_req, max_reached, remaining_cap,Min_req, Max_reached, Remaining_cap= ([0]*(len(a)+1) for _ in range(6))
for i in range(1,len(a)):
if b[i-1] > a[i-1]+remaining_cap[i-1]:
if c-max_reached[i-1] < b[i-1]-remaining_cap[i-1]-a[i-1]:
return 0
min_req[i] = min_req[i-1] + b[i-1]-remaining_cap[i-1]-a[i-1]
remaining_cap[i] = 0
max_reached[i] = max(max_reached[i-1]+b[i-1]-remaining_cap[i-1]-a[i-1],b[i-1])
else:
min_req[i] = min_req[i-1]
remaining_cap[i] = min(remaining_cap[i-1]+a[i-1], c) - b[i-1]
max_reached[i] = max(max_reached[i-1],min(remaining_cap[i-1]+a[i-1], c))
for i in range(len(a)-1,0,-1):
if Min_req[i+1] + b[i] > c:
return 0
if b[i] > a[i]:
Min_req[i] = Min_req[i+1] + b[i]-a[i]
Remaining_cap[i] = Remaining_cap[i+1]
Max_reached[i] = max(Max_reached[i+1], a[i]+Min_req[i])
elif a[i]-b[i]>Min_req[i+1]:
Min_req[i] = 0
Remaining_cap[i] = Remaining_cap[i+1] + min(c-Max_reached[i+1], a[i]-b[i]-Min_req[i+1])
Max_reached[i] = max(a[i], min(c, Max_reached[i+1]+a[i]-b[i]-Min_req[i+1]))
else:
Min_req[i] = Min_req[i+1] + b[i]-a[i]
Remaining_cap[i] = Remaining_cap[i+1]
Max_reached[i] = max(Max_reached[i+1], Min_req[i]+a[i])
ans = 0
if min_req[1] == 0 and remaining_cap[1] >= Min_req[1]:
ans = 1
for i in range(1,len(a)):
if Min_req[i] == 0 and Remaining_cap[i] >= min_req[i]:
ans += 1
return ans
While you try to find out whether you can get from city i back to city i, you need to gather information about previous cities. I'd create a stack containing information that you could start at city x, and arrive at city y with z fuel in the tank.
When you check out city j, you find that you can put X fuel in the tank at j, and driving to j+1 takes Y fuel. If X >= Y, you put that information on the stack. Otherwise, pop the top of the stack. The information there will tell you that you could start at some x and arrive at j with z fuel in the tank. Starting at x, you would leave j with min (z + X, C) in the tank. If that is enough, push the information back on the stack. If not, pop the next item from the stack. If the stack is empty, there is no way to reach j+1.
Now you need to figure out how to end the search, and prove that there are only O (N) operations.
Simpler method: You have your list of cities, and one by one you remove the ones where you cannot start.
You look for the first city i that hasn't enough fuel to get to city i+1. If there is no such city, you can start anywhere. Since you can't get from i to i+1, you remove it from the list of cities, but you need to combine it with the previous one. If the previous city has x fuel and needs y, x >= y, and city i has X fuel and needs Y you do the following:
Replace X with min (X, C - (x - y)) (because the extra fuel can't be used).
Subtract min (y, X) from y and X (because that's you much you can refill)
Replace x with min (C, x + X) and y with y + Y.
At that point, you check the previous city again. You finish when you can go from each city to the next. You may end up with one city that can't reach the next one; in that case you fail.
static int n = 3;
static int c = 3;
static int a[] = {3, 1, 2};
static int b[] = {2, 2, 2};
static int currentCity;
public static void main(String[] args) {
List<String> citi = new ArrayList<String>();
//try one by one
for(int i = 0; i < n; i ++){
currentCity = i;
if(!startFrom(i, 0))
continue;
citi.add("citi" + i);
}
for (String s: citi)
System.out.println(s);
}
public static boolean startFrom(int i, int left){
int tankVal = (a[i] + left) > c ? c : (a[i] + left);
if(b[i] > tankVal)
return false;
left = tankVal - b[i];
int next = (i + 1) % n;
if(next == currentCity)
return true;
return startFrom(next, left);
}
Suppose you are a thief and you invaded a house. Inside you found the following items:
A vase that weights 3 pounds and is worth 50 dollars.
A silver nugget that weights 6 pounds and is worth 30 dollars.
A painting that weights 4 pounds and is worth 40 dollars.
A mirror that weights 5 pounds and is worth 10 dollars.
Solution to this Knapsack problem of size 10 pounds is 90 dollars .
Table made from dynamic programming is :-
Now i want to know which elements i put in my sack using this table then how to back track ??
From your DP table we know f[i][w] = the maximum total value of a subset of items 1..i that has total weight less than or equal to w.
We can use the table itself to restore the optimal packing:
def reconstruct(i, w): # reconstruct subset of items 1..i with weight <= w
# and value f[i][w]
if i == 0:
# base case
return {}
if f[i][w] > f[i-1][w]:
# we have to take item i
return {i} UNION reconstruct(i-1, w - weight_of_item(i))
else:
# we don't need item i
return reconstruct(i-1, w)
I have an iterative algorithm inspired by #NiklasB. that works when a recursive algorithm would hit some kind of recursion limit.
def reconstruct(i, w, kp_soln, weight_of_item):
"""
Reconstruct subset of items i with weights w. The two inputs
i and w are taken at the point of optimality in the knapsack soln
In this case I just assume that i is some number from a range
0,1,2,...n
"""
recon = set()
# assuming our kp soln converged, we stopped at the ith item, so
# start here and work our way backwards through all the items in
# the list of kp solns. If an item was deemed optimal by kp, then
# put it in our bag, otherwise skip it.
for j in range(0, i+1)[::-1]:
cur_val = kp_soln[j][w]
prev_val = kp_soln[j-1][w]
if cur_val > prev_val:
recon.add(j)
w = w - weight_of_item[j]
return recon
Using a loop :
for (int n = N, w = W; n > 0; n--)
{
if (sol[n][w] != 0)
{
selected[n] = 1;
w = w - wt[n];
}
else
selected[n] = 0;
}
System.out.print("\nItems with weight ");
for (int i = 1; i < N + 1; i++)
if (selected[i] == 1)
System.out.print(val[i] +" ");
I'm stuck on a code challenge, and I want a hint.
PROBLEM: You are given a tree data structure (without cycles) and are asked to remove as many "edges" (connections) as possible, creating smaller trees with even numbers of nodes. This problem is always solvable as there are an even number of nodes and connections.
Your task is to count the removed edges.
Input:
The first line of input contains two integers N and M. N is the number of vertices and M is the number of edges. 2 <= N <= 100.
Next M lines contains two integers ui and vi which specifies an edge of the tree. (1-based index)
Output:
Print the number of edges removed.
Sample Input
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
Sample Output :
2
Explanation : On removing the edges (1, 3) and (1, 6), we can get the desired result.
I used BFS to travel through the nodes.
First, maintain an array separately to store the total number of child nodes + 1.
So, you can initially assign all the leaf nodes with value 1 in this array.
Now start from the last node and count the number of children for each node. This will work in bottom to top manner and the array that stores the number of child nodes will help in runtime to optimize the code.
Once you get the array after getting the number of children nodes for all the nodes, just counting the nodes with even number of nodes gives the answer. Note: I did not include root node in counting in final step.
This is my solution. I didn't use bfs tree, just allocated another array for holding eachnode's and their children nodes total number.
import java.util.Scanner;
import java.util.Arrays;
public class Solution {
public static void main(String[] args) {
int tree[];
int count[];
Scanner scan = new Scanner(System.in);
int N = scan.nextInt(); //points
int M = scan.nextInt();
tree = new int[N];
count = new int[N];
Arrays.fill(count, 1);
for(int i=0;i<M;i++)
{
int u1 = scan.nextInt();
int v1 = scan.nextInt();
tree[u1-1] = v1;
count[v1-1] += count[u1-1];
int root = tree[v1-1];
while(root!=0)
{
count[root-1] += count[u1-1];
root = tree[root-1];
}
}
System.out.println("");
int counter = -1;
for(int i=0;i<count.length;i++)
{
if(count[i]%2==0)
{
counter++;
}
}
System.out.println(counter);
}
}
If you observe the input, you can see that it is quite easy to count the number of nodes under each node. Consider (a b) as the edge input, in every case, a is the child and b is the immediate parent. The input always has edges represented bottom-up.
So its essentially the number of nodes which have an even count(Excluding the root node). I submitted the below code on Hackerrank and all the tests passed. I guess all the cases in the input satisfy the rule.
def find_edges(count):
root = max(count)
count_even = 0
for cnt in count:
if cnt % 2 == 0:
count_even += 1
if root % 2 == 0:
count_even -= 1
return count_even
def count_nodes(edge_list, n, m):
count = [1 for i in range(0, n)]
for i in range(m-1,-1,-1):
count[edge_list[i][1]-1] += count[edge_list[i][0]-1]
return find_edges(count)
I know that this has already been answered here lots and lots of time. I still want to know reviews on my solution here. I tried to construct the child count as the edges were coming through the input and it passed all the test cases.
namespace Hackerrank
{
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main(string[] args)
{
var tempArray = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x)).ToList();
int verticeNumber = tempArray[0];
int edgeNumber = tempArray[1];
Dictionary<int, int> childCount = new Dictionary<int, int>();
Dictionary<int, int> parentDict = new Dictionary<int, int>();
for (int count = 0; count < edgeNumber; count++)
{
var nodes = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x)).ToList();
var node1 = nodes[0];
var node2 = nodes[1];
if (childCount.ContainsKey(node2))
childCount[node2]++;
else childCount.Add(node2, 1);
var parent = node2;
while (parentDict.ContainsKey(parent))
{
var par = parentDict[parent];
childCount[par]++;
parent = par;
}
parentDict[node1] = node2;
}
Console.WriteLine(childCount.Count(x => x.Value % 2 == 1) - 1);
}
}
}
My first inclination is to work up from the leaf nodes because you cannot cut their edges as that would leave single-vertex subtrees.
Here's the approach that I used to successfully pass all the test cases.
Mark vertex 1 as the root
Starting at the current root vertex, consider each child. If the sum total of the child and all of its children are even, then you can cut that edge
Descend to the next vertex (child of root vertex) and let that be the new root vertex. Repeat step 2 until you have traversed all of the nodes (depth first search).
Here's the general outline of an alternative approach:
Find all of the articulation points in the graph.
Check each articulation point to see if edges can be removed there.
Remove legal edges and look for more articulation points.
Solution - Traverse all the edges, and count the number of even edges
If we remove an edge from the tree and it results in two tree with even number of vertices, let's call that edge - even edge
If we remove an edge from the tree and it results in two trees with odd
number of vertices, let's call that edge - odd edge
Here is my solution in Ruby
num_vertices, num_edges = gets.chomp.split(' ').map { |e| e.to_i }
graph = Graph.new
(1..num_vertices).to_a.each do |vertex|
graph.add_node_by_val(vertex)
end
num_edges.times do |edge|
first, second = gets.chomp.split(' ').map { |e| e.to_i }
graph.add_edge_by_val(first, second, 0, false)
end
even_edges = 0
graph.edges.each do |edge|
dup = graph.deep_dup
first_tree = nil
second_tree = nil
subject_edge = nil
dup.edges.each do |e|
if e.first.value == edge.first.value && e.second.value == edge.second.value
subject_edge = e
first_tree = e.first
second_tree = e.second
end
end
dup.remove_edge(subject_edge)
if first_tree.size.even? && second_tree.size.even?
even_edges += 1
end
end
puts even_edges
Note - Click Here to check out the code for Graph, Node and Edge classes
Is there anyway to ensure the that the fewest number of turns heuristic is met by anything except a breadth first search? Perhaps some more explanation would help.
I have a random graph, much like this:
0 1 1 1 2
3 4 5 6 7
9 a 5 b c
9 d e f f
9 9 g h i
Starting in the top left corner, I need to know the fewest number of steps it would take to get to the bottom right corner. Each set of connected colors is assumed to be a single node, so for instance in this random graph, the three 1's on the top row are all considered a single node, and every adjacent (not diagonal) connected node is a possible next state. So from the start, possible next states are the 1's in the top row or 3 in the second row.
Currently I use a bidirectional search, but the explosiveness of the tree size ramps up pretty quickly. For the life of me, I haven't been able to adjust the problem so that I can safely assign weights to the nodes and have them ensure the fewest number of state changes to reach the goal without it turning into a breadth first search. Thinking of this as a city map, the heuristic would be the fewest number of turns to reach the goal.
It is very important that the fewest number of turns is the result of this search as that value is part of the heuristic for a more complex problem.
You said yourself each group of numbers represents one node, and each node is connected to adjascent nodes. Then this is a simple shortest-path problem, and you could use (for instance) Dijkstra's algorithm, with each edge having weight 1 (for 1 turn).
This sounds like Dijkstra's algorithm. The hardest part would lay in properly setting up the graph (keeping track of which node gets which children), but if you can devote some CPU cycles to that, you'd be fine afterwards.
Why don't you want a breadth-first search?
Here.. I was bored :-) This is in Ruby but may get you started. Mind you, it is not tested.
class Node
attr_accessor :parents, :children, :value
def initialize args={}
#parents = args[:parents] || []
#children = args[:children] || []
#value = args[:value]
end
def add_parents *args
args.flatten.each do |node|
#parents << node
node.add_children self unless node.children.include? self
end
end
def add_children *args
args.flatten.each do |node|
#children << node
node.add_parents self unless node.parents.include? self
end
end
end
class Graph
attr_accessor :graph, :root
def initialize args={}
#graph = args[:graph]
#root = Node.new
prepare_graph
#root = #graph[0][0]
end
private
def prepare_graph
# We will iterate through the graph, and only check the values above and to the
# left of the current cell.
#graph.each_with_index do |row, i|
row.each_with_index do |cell, j|
cell = Node.new :value => cell #in-place modification!
# Check above
unless i.zero?
above = #graph[i-1][j]
if above.value == cell.value
# Here it is safe to do this: the new node has no children, no parents.
cell = above
else
cell.add_parents above
above.add_children cell # Redundant given the code for both of those
# methods, but implementations may differ.
end
end
# Check to the left!
unless j.zero?
left = #graph[i][j-1]
if left.value == cell.value
# Well, potentially it's the same as the one above the current cell,
# so we can't just set one equal to the other: have to merge them.
left.add_parents cell.parents
left.add_children cell.children
cell = left
else
cell.add_parents left
left.add_children cell
end
end
end
end
end
end
#j = 0, 1, 2, 3, 4
graph = [
[3, 4, 4, 4, 2], # i = 0
[8, 3, 1, 0, 8], # i = 1
[9, 0, 1, 2, 4], # i = 2
[9, 8, 0, 3, 3], # i = 3
[9, 9, 7, 2, 5]] # i = 4
maze = Graph.new :graph => graph
# Now, going from maze.root on, we have a weighted graph, should it matter.
# If it doesn't matter, you can just count the number of steps.
# Dijkstra's algorithm is really simple to find in the wild.
This looks like same problem as this projeceuler http://projecteuler.net/index.php?section=problems&id=81
Comlexity of solution is O(n) n-> number of nodes
What you need is memoization.
At each step you can get from max 2 directions. So pick the solution that is cheaper.
It is something like (just add the code that takes 0 if on boarder)
for i in row:
for j in column:
matrix[i][j]=min([matrix[i-1][j],matrix[i][j-1]])+matrix[i][j]
And now you have lest expensive solution if you move just left or down
Solution is in matrix[MAX_i][MAX_j]
If you can go left and up too, than the BigO is much higher (I can figure out optimal solution)
In order for A* to always find the shortest path, your heuristic needs to always under-estimate the actual cost (the heuristic is "admissable"). Simple heuristics like using the Euclidean or Manhattan distance on a grid work well because they're fast to compute and are guaranteed to be less than or equal to the actual cost.
Unfortunately, in your case, unless you can make some simplifying assumptions about the size/shape of the nodes, I'm not sure there's much you can do. For example, consider going from A to B in this case:
B 1 2 3 A
C 4 5 6 D
C 7 8 9 C
C e f g C
C C C C C
The shortest path would be A -> D -> C -> B, but using spatial information would probably give 3 a lower heuristic cost than D.
Depending on your circumstances, you might be able to live with a solution that isn't actually the shortest path, as long as you can get the answer sooner. There's a nice blogpost here by Christer Ericson (progammer for God of War 3 on PS3) on the topic: http://realtimecollisiondetection.net/blog/?p=56
Here's my idea for an nonadmissable heuristic: from the point, move horizontally until you're even with the goal, then move vertically until you reach it, and count the number of state changes that you made. You can compute other test paths (e.g. vertically then horizontally) too, and pick the minimum value as your final heuristic. If your nodes are roughly equal size and regularly shaped (unlike my example), this might do pretty well. The more test paths you do, the more accurate you'd get, but the slower it would be.
Hope that's helpful, let me know if any of it doesn't make sense.
This untuned C implementation of breadth-first search can chew through a 100-by-100 grid in less than 1 msec. You can probably do better.
int shortest_path(int *grid, int w, int h) {
int mark[w * h]; // for each square in the grid:
// 0 if not visited
// 1 if not visited and slated to be visited "now"
// 2 if already visited
int todo1[4 * w * h]; // buffers for two queues, a "now" queue
int todo2[4 * w * h]; // and a "later" queue
int *readp; // read position in the "now" queue
int *writep[2] = {todo1 + 1, 0};
int x, y, same;
todo1[0] = 0;
memset(mark, 0, sizeof(mark));
for (int d = 0; ; d++) {
readp = (d & 1) ? todo2 : todo1; // start of "now" queue
writep[1] = writep[0]; // end of "now" queue
writep[0] = (d & 1) ? todo1 : todo2; // "later" queue (empty)
// Now consume the "now" queue, filling both the "now" queue
// and the "later" queue as we go. Points in the "now" queue
// have distance d from the starting square. Points in the
// "later" queue have distance d+1.
while (readp < writep[1]) {
int p = *readp++;
if (mark[p] < 2) {
mark[p] = 2;
x = p % w;
y = p / w;
if (x > 0 && !mark[p-1]) { // go left
mark[p-1] = same = (grid[p-1] == grid[p]);
*writep[same]++ = p-1;
}
if (x + 1 < w && !mark[p+1]) { // go right
mark[p+1] = same = (grid[p+1] == grid[p]);
if (y == h - 1 && x == w - 2)
return d + !same;
*writep[same]++ = p+1;
}
if (y > 0 && !mark[p-w]) { // go up
mark[p-w] = same = (grid[p-w] == grid[p]);
*writep[same]++ = p-w;
}
if (y + 1 < h && !mark[p+w]) { // go down
mark[p+w] = same = (grid[p+w] == grid[p]);
if (y == h - 2 && x == w - 1)
return d + !same;
*writep[same]++ = p+w;
}
}
}
}
}
This paper has a slightly faster version of Dijsktra's algorithm, which lowers the constant term. Still O(n) though, since you are really going to have to look at every node.
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.54.8746&rep=rep1&type=pdf
EDIT: THE PREVIOUS VERSION WAS WRONG AND WAS FIXED
Since a Djikstra is out. I'll recommend a simple DP, which has the benefit of running in the optimal time and not having you construct a graph.
D[a][b] is the minimal distance to x=a and y=b using only nodes where the x<=a and y<=b.
And since you can't move diagonally you only have to look at D[a-1][b] and D[a][b-1] when calculating D[a][b]
This gives you the following recurrence relationship:
D[a][b] = min(if grid[a][b] == grid[a-1][b] then D[a-1][b] else D[a-1][b] + 1, if grid[a][b] == grid[a][b-1] then D[a][b-1] else D[a][b-1] + 1)
However doing only the above fails on this case:
0 1 2 3 4
5 6 7 8 9
A b d e g
A f r t s
A z A A A
A A A f d
Therefore you need to cache the minimum of each group of node you found so far. And instead of looking at D[a][b] you look at the minimum of the group at grid[a][b].
Here's some Python code:
Note grid is the grid that you're given as input and it's assumed the grid is N by N
groupmin = {}
for x in xrange(0, N):
for y in xrange(0, N):
groupmin[grid[x][y]] = N+1#N+1 serves as 'infinity'
#init first row and column
groupmin[grid[0][0]] = 0
for x in xrange(1, N):
gm = groupmin[grid[x-1][0]]
temp = (gm) if grid[x][0] == grid[x-1][0] else (gm + 1)
groupmin[grid[x][0]] = min(groupmin[grid[x][0]], temp);
for y in xrange(1, N):
gm = groupmin[grid[0][y-1]]
temp = (gm) if grid[0][y] == grid[0][y-1] else (gm + 1)
groupmin[grid[0][y]] = min(groupmin[grid[0][y]], temp);
#do the rest of the blocks
for x in xrange(1, N):
for y in xrange(1, N):
gma = groupmin[grid[x-1][y]]
gmb = groupmin[grid[x][y-1]]
a = (gma) if grid[x][y] == grid[x-1][y] else (gma + 1)
b = (gmb) if grid[x][y] == grid[x][y-1] else (gma + 1)
temp = min(a, b)
groupmin[grid[x][y]] = min(groupmin[grid[x][y]], temp);
ans = groupmin[grid[N-1][N-1]]
This will run in O(N^2 * f(x)) where f(x) is the time the hash function takes which is normally O(1) time and this is one of the best functions you can hope for and it has a lot lower constant factor than Djikstra's.
You should easily be able to handle N's of up to a few thousand in a second.
Is there anyway to ensure the that the fewest number of turns heuristic is met by anything except a breadth first search?
A faster way, or a simpler way? :)
You can breadth-first search from both ends, alternating, until the two regions meet in the middle. This will be much faster if the graph has a lot of fanout, like a city map, but the worst case is the same. It really depends on the graph.
This is my implementation using a simple BFS. A Dijkstra would also work (substitute a stl::priority_queue that sorts by descending costs for the stl::queue) but would seriously be overkill.
The thing to notice here is that we are actually searching on a graph whose nodes do not exactly correspond to the cells in the given array. To get to that graph, I used a simple DFS-based floodfill (you could also use BFS, but DFS is slightly shorter for me). What that does is to find all connected and same character components and assign them to the same colour/node. Thus, after the floodfill we can find out what node each cell belongs to in the underlying graph by looking at the value of colour[row][col]. Then I just iterate over the cells and find out all the cells where adjacent cells do not have the same colour (i.e. are in different nodes). These therefore are the edges of our graph. I maintain a stl::set of edges as I iterate over the cells to eliminate duplicate edges. After that it is a simple matter of building an adjacency list from the list of edges and we are ready for a bfs.
Code (in C++):
#include <queue>
#include <vector>
#include <iostream>
#include <string>
#include <set>
#include <cstring>
using namespace std;
#define SIZE 1001
vector<string> board;
int colour[SIZE][SIZE];
int dr[]={0,1,0,-1};
int dc[]={1,0,-1,0};
int min(int x,int y){ return (x<y)?x:y;}
int max(int x,int y){ return (x>y)?x:y;}
void dfs(int r, int c, int col, vector<string> &b){
if (colour[r][c]<0){
colour[r][c]=col;
for(int i=0;i<4;i++){
int nr=r+dr[i],nc=c+dc[i];
if (nr>=0 && nr<b.size() && nc>=0 && nc<b[0].size() && b[nr][nc]==b[r][c])
dfs(nr,nc,col,b);
}
}
}
int flood_fill(vector<string> &b){
memset(colour,-1,sizeof(colour));
int current_node=0;
for(int i=0;i<b.size();i++){
for(int j=0;j<b[0].size();j++){
if (colour[i][j]<0){
dfs(i,j,current_node,b);
current_node++;
}
}
}
return current_node;
}
vector<vector<int> > build_graph(vector<string> &b){
int total_nodes=flood_fill(b);
set<pair<int,int> > edge_list;
for(int r=0;r<b.size();r++){
for(int c=0;c<b[0].size();c++){
for(int i=0;i<4;i++){
int nr=r+dr[i],nc=c+dc[i];
if (nr>=0 && nr<b.size() && nc>=0 && nc<b[0].size() && colour[nr][nc]!=colour[r][c]){
int u=colour[r][c], v=colour[nr][nc];
if (u!=v) edge_list.insert(make_pair(min(u,v),max(u,v)));
}
}
}
}
vector<vector<int> > graph(total_nodes);
for(set<pair<int,int> >::iterator edge=edge_list.begin();edge!=edge_list.end();edge++){
int u=edge->first,v=edge->second;
graph[u].push_back(v);
graph[v].push_back(u);
}
return graph;
}
int bfs(vector<vector<int> > &G, int start, int end){
vector<int> cost(G.size(),-1);
queue<int> Q;
Q.push(start);
cost[start]=0;
while (!Q.empty()){
int node=Q.front();Q.pop();
vector<int> &adj=G[node];
for(int i=0;i<adj.size();i++){
if (cost[adj[i]]==-1){
cost[adj[i]]=cost[node]+1;
Q.push(adj[i]);
}
}
}
return cost[end];
}
int main(){
string line;
int rows,cols;
cin>>rows>>cols;
for(int r=0;r<rows;r++){
line="";
char ch;
for(int c=0;c<cols;c++){
cin>>ch;
line+=ch;
}
board.push_back(line);
}
vector<vector<int> > actual_graph=build_graph(board);
cout<<bfs(actual_graph,colour[0][0],colour[rows-1][cols-1])<<"\n";
}
This is just a quick hack, lots of improvements can be made. But I think it is pretty close to optimal in terms of runtime complexity, and should run fast enough for boards of size of several thousand (don't forget to change the #define of SIZE). Also, I only tested it with the one case you have provided. So, as Knuth said, "Beware of bugs in the above code; I have only proved it correct, not tried it." :).