#include <iostream>
#include <vector>
#include <bitset>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <utility>
using namespace std;
vector<int> p(100001),rnk(100001,1),child(100001);
vector<long long int> sum(400020);
vector<pair<int,pair<int,int> > > ed;
vector<vector<pair<int,int> > > mst(100001);
int n,e;
bitset<100001> vis;
int find(int a){
return p[a]==a?a:p[a]=find(p[a]);
}
bool same(int a,int b){
return find(a)==find(b);
}
void merge(int a,int b){
if(!same(a,b)){
if(rnk[find(a)]>rnk[find(b)]){
p[find(b)]=find(a);
}
else {
p[find(a)]=find(b);
}
if(rnk[find(a)]==rnk[find(b)])
rnk[find(b)]++;
}
}
int dfs(int u){
vis[u]=1;
int ans=1;
for(int i=0;i<mst[u].size();i++){
if(!vis[mst[u][i].second]){
ans+=dfs(mst[u][i].second);
sum[mst[u][i].first]+=(long long)(n-child[mst[u][i].second])*child[mst[u][i].second];
}
}
return child[u]=ans;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>e;
for(int i=1;i<=n;i++)
p[i]=i;
for(int i=0;i<e;i++){
int x,y,w;
cin>>x>>y>>w;
ed.push_back({w,{x,y}});
}
sort(ed.begin(),ed.end());
for(int i=0;i<ed.size();i++){
if(!same(ed[i].second.first,ed[i].second.second)){
mst[ed[i].second.first].push_back({ed[i].first,ed[i].second.second});
mst[ed[i].second.second].push_back({ed[i].first,ed[i].second.first});
merge(ed[i].second.first,ed[i].second.second);
}
}
dfs(1);
for(int i=0;i<2*e+10;i++){
sum[i+1]+=sum[i]/2;
sum[i]%=2;
}
int hsb=2*e+10;
while(hsb>0&&sum[hsb]==0){
hsb--;
}
for(int i=hsb;i>=0;i--)
cout<<sum[i];
cout<<endl;
return 0;
}
#include <vector>
#include <bitset>
#include <queue>
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <utility>
using namespace std;
vector<int> p(100001),rnk(100001,1),child(100001);
vector<long long int> sum(400020);
vector<pair<int,pair<int,int> > > ed;
vector<vector<pair<int,int> > > mst(100001);
int n,e;
bitset<100001> vis;
int find(int a){
return p[a]==a?a:p[a]=find(p[a]);
}
bool same(int a,int b){
return find(a)==find(b);
}
void merge(int a,int b){
if(!same(a,b)){
if(rnk[find(a)]>rnk[find(b)]){
p[find(b)]=find(a);
}
else {
p[find(a)]=find(b);
}
if(rnk[find(a)]==rnk[find(b)])
rnk[find(b)]++;
}
}
int dfs(int u){
vis[u]=1;
int ans=1;
for(int i=0;i<mst[u].size();i++){
if(!vis[mst[u][i].second]){
ans+=dfs(mst[u][i].second);
sum[mst[u][i].first]+=(long long)(n-child[mst[u][i].second])*child[mst[u][i].second];
}
}
return child[u]=ans;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>e;
for(int i=1;i<=n;i++)
p[i]=i;
for(int i=0;i<e;i++){
int x,y,w;
cin>>x>>y>>w;
ed.push_back({w,{x,y}});
}
sort(ed.begin(),ed.end());
for(int i=0;i<ed.size();i++){
if(!same(ed[i].second.first,ed[i].second.second)){
mst[ed[i].second.first].push_back({ed[i].first,ed[i].second.second});
mst[ed[i].second.second].push_back({ed[i].first,ed[i].second.first});
merge(ed[i].second.first,ed[i].second.second);
}
}
dfs(1);
for(int i=0;i<2*e+10;i++){
sum[i+1]+=sum[i]/2;
sum[i]%=2;
}
int hsb=2*e+10;
while(hsb>0&&sum[hsb]==0){
hsb--;
}
for(int i=hsb;i>=0;i--)
cout<<sum[i];
cout<<endl;
return 0;
}
Can you explain this as well.
ReplyDeleteSure. This is a simple problem. We are asked to build a Minimum Spanning Tree. I did that using UFDS (Union Find Disjoint Set). It is a data structure used to organize discrete elements in multiple sets, such that an element belong to only one set. If you know this data structure, the problem becomes very easy. If you don't know it,then you can learn it or you can implement a solution using priority queue instead. This algorithm is named Kruskal's MST. The priority queue version is called Prim's MST.
DeleteHowever, I would recommend that you should learn the UFDS.
Thanks i got that part of MST. What i did not get is the rest part. I tried it ,any times in python as nelow.
ReplyDelete#!/bin/python
import sys
sys.setrecursionlimit(1000000000)
from collections import *
import heapq
import sys
graph=defaultdict(dict)
answer=0
n,m = raw_input().strip().split(' ')
n,m = [int(n),int(m)]
for a1 in xrange(0,m):
x,y,r = map(int,raw_input().strip().split(' '))
z = 1<<r
if y in graph[x]:
if z < graph[x][y]:
graph[x][y] = z
graph[y][x] = z
else:
pass
else:
graph[x][y] = z
graph[y][x] = z
def dfs(node,graph1,numcities):
if node not in visited:
visited[node]=1
for vertex,weight in graph1[node].items():
countnumpaths[node][vertex] = countnumpaths.get(node,{}).get(vertex,0) + 1
countnumpaths[vertex][node] = countnumpaths.get(vertex,{}).get(node,0) + 1
numcities[vertex]+=1
dfs(vertex,graph1,numcities)
parent=[-1]*(n+1)
visited={};heap=[];heapq.heappush(heap,(0,1))
distance = [sys.maxint]*(n+1)
distance[1] = 0
while heap:
weight,node = heapq.heappop(heap)
if node not in visited:
visited[node] = 0
for node_c,weight_c in graph[node].items():
newdist = weight+weight_c
if newdist < distance[node_c]:
distance[node_c] = newdist
parent[node_c] = node
heapq.heappush(heap,(newdist,node_c))
graph1=defaultdict(dict)
for i in range(2,n+1):
graph1[parent[i]][i] = graph[parent[i]][i]
graph1[i][parent[i]] = graph[parent[i]][i]
visited={}
countnumpaths=defaultdict(dict);numcities=[0]*(n+1)
dfs(1,graph1,numcities)
visited={}
for i in range(1,n+1):
for k,v in countnumpaths[i].items():
if (i,k) not in visited:
visited[(i,k)]=1;visited[(k,i)]=1
answer = answer + (v*(n-v-1))*graph[i][k] if numcities[i] <= 1 or numcities[k] <=1 else answer + (v*(n-v))*graph[i][k]
print bin(answer)[2:]
If you cam explain the rest part after building he mst, that will help.
Hi Sir, could you please be merciful and explain to me what does the following mean:
ReplyDeletevector sum(400020); Thanks for your time
Hi bro, 'sum' is just a variable name, its not a keyword. This means its not a C++ command. 'sum' is name of vector that stores the answer.
Delete400020 is the length of the vector. While initializing a vector we can specify size of vector, all elements then get 0 as default value.
Deleteafter dsu part how have you computed dist bw every pair of cities..plz explain
ReplyDeleteDistance between pair of cities connected by edge was given in the question. The usual solution would be to calculate shortest paths between all pais. But that approach would be too slow.
DeleteInstead, we can take advantage of the fact that - if you added powers of 2 of distinct exponents , the result can not be greater than a power of two with any other greater exponent. For example: 2^1+2^2+2^5+2^8 < 2^9. Try to convince yourself of this.
And I strongly suggest you take a look at 'Graphs' section at https://cp-algorithms.com/ or some other resource like 'Tushar Roy's Graph Playlist' on YouTube.
The 'sum of distinct exponents of 2' idea allows us to tackle the problem as a 'Minimum Spanning Tree' - which is more efficient than computing 'All pairs shortest path'.
DeleteCould you plz explain
ReplyDeletefor(int i=0;i<2*e+10;i++){
sum[i+1]+=sum[i]/2;
sum[i]%=2;
}
int hsb=2*e+10;
while(hsb>0&&sum[hsb]==0){
hsb--;
}
for(int i=hsb;i>=0;i--)
cout<<sum[i];
??????????????
The first 'for loop' ensures the answer is valid binary number, i.e. carry of current position is added to next higher bit. This carry works just as in decimal system we ensure no digit is more than '9'.
ReplyDeleteThe middle part of code checks for 'highest set bit' in the answer, i.e. the highest power of '2' which is part of solution.
The last 'for loop' prints the output.
Sorry for the late reply : )
Deletehow is it guaranteed that all the pairs shortest paths are always contained in this MST?
ReplyDeleteFor Example: n=5 m=5 and a b c are
1 2 1
2 3 2
3 4 4
4 5 5
1 5 3
here all lengths of paths are distinct(as given in question) and Its MST will be
1 2 1
2 3 2
3 4 4
1 5 3
so according MST distance for going from node 4 to node 5 will be 4+2+1+3=8
BUT from actual given graph we have a path from node 4 to node 5 (which is dropped while making MST) which is of length 5 only.
The input C_i represents a distance of 2^(C_i). So in your example, the distance is 2^4 + 2^2 + 2^1 + 2^3 = 30. Whereas the alternate path you suggest has distance 2^5 = 32; which is clearly larger. Note that 2^i is always larger than sum of (2^j)'s when j < i. Ex - 10000 (16) > 01111 (15).
DeleteWhy we are doing dfs after Finding MST ?
ReplyDelete