Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- D.E. Shaw | Off-Campus | 2023 Batch
- Problem statement
- There is an undirected graph of g_nodes nodes numbered from 1 to g_nodes and g_edges where the ith edge connects the nodes numbered g_from[i] and g_to[i]. There is also an array of m integers, disconnected_nodes, which represents the array of nodes that are not reachable from one another via any path. No two nodes in the array are connected directly or indirectly.
- Find the maximum number of edges that can be added to the graph such that the set of disconnected_nodes remain disconnected, the graph does not contain any self-loops, and there are no multiple edges between two nodes.
- Example
- g_nodes = 4 , disconnected_nodes = [1, 3]
- g_from = [1], g_to = [2]
- The optimal solution is to connect node 4 to nodes 1 and 2. This adds a total of 2 edges. No more edges can be added as nodes 1 and 3 cannot have a path between them
- Testcase
- Input:
- g_nodes = 6
- g_edges = 4
- g_from = [1,1,2,4]
- g_to = [2,3,3,5]
- disconnected_nodes = [2,4]
- Output:
- 3
- Explanation: 3 edges can be added to the graph, node 6 can be connected to nodes 1, 2 and 3
- It can be shown that 3 is maximum number of edges that we can add
- */
- -------------------------------------------------------------------------------------------------------------------------------------
- THOUGHT PROCESS
- 1) Find graphs with no forbidden nodes, and merge them
- 2) Find the largest node count from subgraph containing forbidden node
- 3) Merge all graphs with no forbidden node and merge largest graph with a forbidden node
- 4) Go to each component and find edges to draw using formula n*(n-1)/2-existing edges, where n is the component nodes and existing edge is the edge that already exists in this component
- -------------------------------------------------------------------------------------------------------------------------------------
- __________CODE_________
- #include <bits/stdc++.h>
- using namespace std;
- vector<int> parent;
- vector<int> dense;
- vector<int> component_count;
- vector<int> edge_count;
- unordered_set<int> unfriendlyNodes;
- void initialise(int n, vector<int> &nodes){
- parent.resize(n+1);
- dense.resize(n+1,0);
- component_count.resize(n+1,1);
- edge_count.resize(n+1,0);
- for(int i=1;i<=n;i++){
- parent[i]=i;
- }
- }
- int findParent(int node){
- if(node==parent[node]){
- return node;
- }
- return parent[node]=findParent(parent[node]);
- }
- void balancer(int par, int child){
- parent[child]=par;
- edge_count[par]+=edge_count[child]+1;
- component_count[par]+=component_count[child];
- edge_count[child]=0;
- edge_count[child]=0;
- }
- void merge(int node1, int node2){
- int Pnode1=findParent(node1);
- int Pnode2=findParent(node2);
- if(Pnode1==Pnode2){
- edge_count[Pnode1]++;
- return;
- }
- if(dense[Pnode1]<dense[Pnode2]){
- balancer(Pnode2,Pnode1);
- }
- else if(dense[Pnode1]>dense[Pnode2]){
- balancer(Pnode1,Pnode2);
- }
- if(dense[Pnode1]==dense[Pnode2]){
- dense[Pnode1]++;
- balancer(Pnode1,Pnode2);
- }
- }
- int helper(int n){
- /* STEP 1: We will filter graphs having no forbidden Nodes */
- unordered_set<int> rep; // contains representative of graphs having no forbidden node
- for(int i=1;i<=n;i++){
- if(unfriendlyNodes.find(findParent(i))==unfriendlyNodes.end()){
- rep.insert(findParent(i));
- }
- }
- /* STEP 2: We will now merge the graphs having no forbiddenNodes to make a super graph */
- int superGraph=-1;
- auto itr=rep.begin();
- if(rep.size()>0){
- superGraph=*itr;
- itr++;
- }
- for(;itr!=rep.end();itr++){
- merge(superGraph,*itr);
- // removing this imaginary edge used to connect two subgraphs
- edge_count[findParent(superGraph)]--;
- }
- /* STEP 3: We will not find the maximum component_count of graph having forbiddenNode */
- int mxnode=-1;
- int mxSize=-1;
- for(auto node: unfriendlyNodes){ // get the highest sized forbidden node
- int representative=findParent(node);
- if(mxSize<component_count[representative]){
- mxnode=representative;
- mxSize=component_count[representative];
- }
- }
- /* STEP 4: We will merge the superGraph with the highest sized forbidden node graph */
- if(superGraph!=-1){ // if there exists a super graph
- merge(superGraph,mxnode);
- // removing this imaginary edge used to connect two subgraphs
- edge_count[findParent(mxnode)]--;
- }
- /* STEP 5: We will now calculate the edges we can make, each component having n nodes can have max
- of total=n*(n-1)/2 edges and if there are already x ExistingEdges, extra edges which can
- be drawn are total-x */
- int res=0;
- unordered_set<int> vis;
- for(int node=1;node<=n;node++){
- if(vis.find(findParent(node))!=vis.end()){
- continue;
- }
- int ExistingEdges=edge_count[findParent(node)];
- int totalConnectedEdges=component_count[findParent(node)]*(component_count[findParent(node)]-1)/2;
- res+=totalConnectedEdges-ExistingEdges;
- vis.insert(findParent(node));
- }
- return res;
- }
- int main(){
- /* BELOW ARE THE TEST CASES */
- // int g_nodes = 7;
- // int g_edges = 6;
- // int g_from[6]= {1, 1, 2, 3, 4, 6};
- // int g_to[6]= {2, 3, 3, 4, 5, 7};
- // vector<int> forbiddenNodes={1,7};
- // initialise(g_nodes,forbiddenNodes);
- // for(int i=0;i<g_edges;i++){
- // merge(g_from[i],g_to[i]);
- // }
- // for(auto node: forbiddenNodes){
- // unfriendlyNodes.insert(findParent(node));
- // }
- // cout<<helper(g_nodes);
- // int g_nodes=4;
- // int g_edges=1;
- // vector<int> forbiddenNodes={1,3};
- // int g_from[g_edges]= {1};
- // int g_to[g_edges]= {2};
- // initialise(g_nodes,forbiddenNodes);
- // for(int i=0;i<g_edges;i++){
- // merge(g_from[i],g_to[i]);
- // }
- // for(auto node: forbiddenNodes){
- // unfriendlyNodes.insert(findParent(node));
- // }
- // cout<<helper(g_nodes);
- // int g_nodes=6;
- // int g_edges=4;
- // vector<int> forbiddenNodes={2,4};
- // int g_from[g_edges]= {1,1,2,4};
- // int g_to[g_edges]= {2,3,3,5};
- // initialise(g_nodes,forbiddenNodes);
- // for(int i=0;i<g_edges;i++){
- // merge(g_from[i],g_to[i]);
- // }
- // for(auto node: forbiddenNodes){
- // unfriendlyNodes.insert(findParent(node));
- // }
- // cout<<helper(g_nodes);
- // int g_nodes=23;
- // int g_edges=18;
- // vector<int> forbiddenNodes={7,17,19};
- // int g_from[g_edges]= {1,1,1,2,3,4,6,8,9,10,11,13,14,15,22,19,19,23};
- // int g_to[g_edges]= {2,3,4,3,4,5,7,9,10,11,12,14,15,16,19,20,21,19};
- // initialise(g_nodes,forbiddenNodes);
- // for(int i=0;i<g_edges;i++){
- // merge(g_from[i],g_to[i]);
- // }
- // for(auto node: forbiddenNodes){
- // unfriendlyNodes.insert(findParent(node));
- // }
- // cout<<helper(g_nodes);
- // int g_nodes=8;
- // int g_edges=6;
- // vector<int> forbiddenNodes={1,8};
- // int g_from[g_edges]= {1, 1, 2, 4, 5, 6};
- // int g_to[g_edges]= {2, 3, 3, 5, 6, 7};
- // initialise(g_nodes,forbiddenNodes);
- // for(int i=0;i<g_edges;i++){
- // merge(g_from[i],g_to[i]);
- // }
- // for(auto node: forbiddenNodes){
- // unfriendlyNodes.insert(findParent(node));
- // }
- // cout<<helper(g_nodes);
- // int g_nodes=7;
- // int g_edges=7;
- // vector<int> forbiddenNodes={1,7};
- // int g_from[g_edges]= {1, 1, 2, 2, 3, 4, 5};
- // int g_to[g_edges]= {2, 3, 3, 4, 5, 5, 6};
- // initialise(g_nodes,forbiddenNodes);
- // for(int i=0;i<g_edges;i++){
- // merge(g_from[i],g_to[i]);
- // }
- // for(auto node: forbiddenNodes){
- // unfriendlyNodes.insert(findParent(node));
- // }
- // cout<<helper(g_nodes);
- int g_nodes=7;
- int g_edges=0;
- vector<int> forbiddenNodes={1,7};
- int g_from[g_edges]= {};
- int g_to[g_edges]= {};
- initialise(g_nodes,forbiddenNodes);
- for(int i=0;i<g_edges;i++){
- merge(g_from[i],g_to[i]);
- }
- for(auto node: forbiddenNodes){
- unfriendlyNodes.insert(findParent(node));
- }
- cout<<helper(g_nodes);
- }
Advertisement
Add Comment
Please, Sign In to add comment