diff --git a/contracts.txt b/contracts.txt index 077c8b4..4e711b4 100644 --- a/contracts.txt +++ b/contracts.txt @@ -6,3 +6,7 @@ 3 Cochin Mumbai 200 3 Mumbai Chennai 300 3 Chennai Cochin 500 +3 Cochin Bangalore 100 +2 Mumbai Kolkata 600 +2 Kolkata Bangalore 400 +3 Kolkata Mumbai 100 diff --git a/contracts_partial.txt b/contracts_partial.txt new file mode 100644 index 0000000..015648b --- /dev/null +++ b/contracts_partial.txt @@ -0,0 +1,5 @@ +2 Bangalore Kolkata 200 +3 Kolkata Mumbai 100 +3 Kolkata Chennai 100 +3 Kolkata Cochin 100 +4 Cochin Bangalore 50 diff --git a/cyclic_contracts.py b/cyclic_contracts.py index de8b04b..7c1552e 100644 --- a/cyclic_contracts.py +++ b/cyclic_contracts.py @@ -9,8 +9,12 @@ class Route(object): self.src = src self.dst = dst + def __eq__(self,rt): + eq = self.route_id == rt.route_id and self.contract_id == rt.contract_id + return eq + def __repr__(self): - return str(self.route_id)+":"+self.src+" - "+self.dst+" "+self.load + return str(self.contract_id)+"-"+str(self.route_id)+":"+self.src+" - "+self.dst+" "+self.load class Contract(object): @@ -44,53 +48,88 @@ class Transporter(object): c_dict[c_id].append(Route(route_id,int(c_id),load,src,dst)) else: c_dict[c_id] = [Route(0,int(c_id),load,src,dst)] - contrants = [] - for c_id in c_dict: - contrants.append(Contract(int(c_id),c_dict[c_id])) - return contrants + contracts = [Contract(int(i),c_dict[i]) for i in sorted(c_dict.keys())] - def routes(self): + return contracts + + def contract_routes(self): all_routes = [] - routes_map = {} for c in self.contracts: for r in c.routes: all_routes.append(r) - if routes_map.has_key(r.src): - routes_map[r.src].append(r) - else: - routes_map[r.src]= [r] - for r in all_routes: - if not routes_map.has_key(r.dst): - routes_map[r.dst]= [] - return routes_map + return all_routes - def is_cyclic(self): - return circular_dep(self.routes()) + def contracts_required(self): + routes = self.contract_routes() + unfulfilled = rem_routes(routes) + print "No of contracts required : ",len(unfulfilled) + if len(unfulfilled) > 0: + print "Contracts from ",repr(unfulfilled) CYCLE_LIMIT = 3 -def find_loop(elem,dep_elem,deps,checked,path): - if dep_elem in checked or not deps.has_key(dep_elem): - return (False,[]) - else: - checked.add(dep_elem) - for c in deps[dep_elem]: - path.append(c) - if elem == c.dst and len(path) <= CYCLE_LIMIT: - return (True,path) - loop_path = find_loop(elem,c.dst,deps,checked,path) - if loop_path[0]: - return loop_path +def rem_routes(routes): + loop_routes = routes + while len(loop_routes)>0: + circ,paths,loop_routes = largest_loop(loop_routes) + if not circ: + break + partial_paths = [] + partial_routes = loop_routes + while len(partial_routes)>0: + lp = longest_path(partial_routes) + partial_paths.append((lp[-1].dst,lp[0].src)) + partial_routes = filter(lambda x:x not in lp,partial_routes) + return partial_paths + +def route_deps(routes): + routes_map = {} + for r in routes: + if routes_map.has_key(r.src): + routes_map[r.src].append(r) else: - del(path[-1]) - return (False,[]) + routes_map[r.src]= [r] + if not routes_map.has_key(r.dst): + routes_map[r.dst]= [] + return routes_map -def circular_dep(deps): - dep_state = [] - for k in deps.keys(): - circ_dep_k = find_loop(k,k,deps,set(),[]) - # print path - dep_state.append((k,circ_dep_k)) - return dep_state +def largest_loop(routes): + deps = route_deps(routes) + circ_paths = [find_loop(r.src,r.src,deps,set(),[]) for r in routes] + circ,paths = max(circ_paths,key=lambda p:len(p[1])) + # print filter(lambda p:not p[0],circ_paths) + rem_paths = filter(lambda x:x not in paths,routes) + return (circ,paths,rem_paths) -print Transporter.from_file('./contracts.txt').is_cyclic() +def longest_path(routes): + def route_path(r,deps): + if not deps.has_key(r.dst) or len(deps[r.dst])==0: + return [r] + all_dep_paths = [([r]+route_path(rt,deps)) for rt in deps[r.dst]] + rp = max(all_dep_paths,key=lambda p:len(p)) + return rp + deps = route_deps(routes) + all_paths = [route_path(r,deps) for r in routes] + longest = max(all_paths,key=len) + return longest + +def find_loop(elem,dep_elem,deps,checked,path): + found_loop = False + if dep_elem not in checked and deps.has_key(dep_elem): + checked.add(dep_elem) + for c in deps[dep_elem]: + path.append(c) + if elem == c.dst and len(path) <= CYCLE_LIMIT: + found_loop = True + break + (loop,path) = find_loop(elem,c.dst,deps,checked,path) + if loop: + found_loop = True + break + else: + del(path[-1]) + return (found_loop,path) + + +# Transporter.from_file('./contracts.txt').contracts_required() +Transporter.from_file('./contracts.txt').contracts_required()