In a city, there is
n
persons and each person has some friends in the city. (if a is friend of b then b is also friend of a) We want to spread a rumor between these persons but saying the rumor to each person has a costc_i
but after that, the person spread the rumor between all of its friends for free.We want to find minimum cost to spread the rumor to all persons in the city. In the input we get
n
: number of persons.m
: number of relations. thenn
integersc_i
: cost of saying the rumor to personi
and then inm
lines, we get two integersu
,v
in each line which indicatesu,v
are friends. (note that number of person start from1
ton
but in arrays we have from0
ton-1
)Also
n,m<=10E5
andc_i<=10E9
I think this problem is equivalent to Sum of the minimum elements in all connected components of an undirected graph.
I found a solution for it in internet with C++ but I wanted to write it in Java and so wrote the program below using dfs. The problem is that when I submit the answer to an online judge in the site where I found the question, it just pass only 3 of 20 tests. I want to know which part of my solution is wrong?
(the site is not in English and is actually an online judge system of a university but if you want it, I can link to the site)
Final Code That completely works fine:
import java.util.LinkedList;
import java.util.Scanner;
class Graph {
int numberOfVertices;
LinkedList<Integer>[] graph;
boolean[] visited;
long[] costs;
Graph(int numberOfVertices,long[] costs) {
this.numberOfVertices = numberOfVertices;
this.graph = new LinkedList[numberOfVertices];
for (int v = 0; v < numberOfVertices; v++) {
graph[v] = new LinkedList<Integer>();
}
this.costs=costs;
this.visited = new boolean[numberOfVertices];
}
void addEdge(int u, int v) {
graph[u].add(v);
graph[v].add(u);
}
long dfs(int node, long mini) {
// Stores the minimum
mini = Math.min(mini, costs[ node]);
// Marks node as visited
visited[ node] = true;
// Traversed in all the connected nodes
for (int i : graph[ node]) {
if (!visited[ i])
mini = dfs(i, mini);
}
return mini;
}
void minimumSumConnectedComponents() {
// Initially sum is 0
long sum = 0L;
// Traverse for all nodes
for (int i = 0; i < numberOfVertices; i++) {
if (!visited[i]) {
sum += dfs(i, costs[i]);
}
}
// Returns the answer
System.out.println(sum);
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int numberOfVertices,numberOfRelations;
numberOfVertices=input.nextInt();
numberOfRelations=input.nextInt();
long [] costs = new long[numberOfVertices];
for (int i =0;i<numberOfVertices;i++)
{
costs[i]=input.nextLong();
}
Graph g = new Graph(numberOfVertices,costs);
for (int i =0;i<numberOfRelations;i++)
{
int v1,v2;
v1=input.nextInt();
v2=input.nextInt();
g.addEdge(v1-1,v2-1);
}
g.minimumSumConnectedComponents();
}
}
Old Code which has some issues:
import java.util.Scanner;
import java.util.Vector;
class Graph {
Integer numberOfVertices;
Vector<Integer>[] graph;
boolean[] visited;
Long[] costs;
Graph(Integer numberOfVertices,Long[] costs) {
this.numberOfVertices = numberOfVertices;
this.graph = new Vector[numberOfVertices];
for (Integer v = 0; v < numberOfVertices; v++) {
graph[v] = new Vector<Integer>();
}
this.costs = new Long[numberOfVertices];
for (Integer v = 0; v < numberOfVertices; v++) {
this.costs[v] = costs[v];
}
this.visited = new boolean[numberOfVertices];
}
void addEdge(Integer u, Integer v) {
graph[u].add(v);
graph[v].add(u);
}
void dfs(Integer node, Long mini) {
// Stores the minimum
mini = Math.min(mini, costs[(Integer) node]);
// Marks node as visited
visited[(Integer) node] = true;
// Traversed in all the connected nodes
for (Integer i : graph[(Integer) node]) {
if (!visited[(Integer) i])
dfs(i, mini);
}
}
void minimumSumConnectedComponents() {
// Initially sum is 0
Long sum = 0L;
// Traverse for all nodes
for (Integer i = 0; i < numberOfVertices; i++) {
if (!visited[i]) {
Long mini = costs[i];
dfs(i, mini);
sum += mini;
}
}
// Returns the answer
System.out.println(sum);
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Integer numberOfVertices,numberOfRelations;
numberOfVertices=input.nextInt();
numberOfRelations=input.nextInt();
Long [] costs = new Long[numberOfVertices];
for (Integer i =0;i<numberOfVertices;i++)
{
costs[i]=input.nextLong();
}
Graph g = new Graph(numberOfVertices,costs);
for (Integer i =0;i<numberOfRelations;i++)
{
Integer v1,v2;
v1=input.nextInt();
v2=input.nextInt();
g.addEdge(v1-1,v2-1);
}
g.minimumSumConnectedComponents();
}
}
Sample Test Cases:
5 2
2 5 3 4 8
1 4
4 5
Expected Output: 10
10 0
1 2 3 4 5 6 7 8 9 10
Expected Output: 55
10 5
1 6 2 7 3 8 4 9 5 10
1 2
3 4
5 6
7 8
9 10
Expected Output: 15
My program pass this sample test cases but it gets wrong answer for a lot of unknown test cases.
These lines don't do what you want:
// Stores the minimum
mini = Math.min(mini, costs[(Integer) node]);
If they mutated the caller's mini
, then your code seems otherwise correct (assuming no stack overflows). My suggestion would be to return the new value of mini
for the caller to use:
Long dfs(Integer node, Long mini) {
// Stores the minimum
mini = Math.min(mini, costs[(Integer) node]);
// Marks node as visited
visited[(Integer) node] = true;
// Traversed in all the connected nodes
for (Integer i : graph[(Integer) node]) {
if (!visited[(Integer) i])
mini = dfs(i, mini);
}
return mini;
}
void minimumSumConnectedComponents() {
// Initially sum is 0
Long sum = 0L;
// Traverse for all nodes
for (Integer i = 0; i < numberOfVertices; i++) {
if (!visited[i]) {
sum += dfs(i, costs[i]);
}
}
// Returns the answer
System.out.println(sum);
}