-4

PROBLEM

Suppose there are 'n' cities in a country out of which, one is the capital. All of the cities are connected through 'n-1' roads that it's possible to travel between any two cities using those roads. Population of cities Pi is provided in the question.

Now if a city is infected with virus, the cities connected with that city also get infected. In the case of an infection a new capital is selected. The non-infected city having the largest population becomes the new capital.

INPUT

The first line of the input contains an integer T denoting the number of test cases. The description of T test cases follows.

The first line of each test case contains one integer N which denotes number of cities.

Next line contains N space-separated integers P1, P2, ..., PN denoting the population of each city.

Next N-1 lines contain two space-separated integers each V and U denoting that there's a road between cities V and U.

Output

For each test case, output a single line containing N integers A1, A2, ..., AN separated by a space. Here Ai denotes the number of the city picked to be new capital in case infection starts spreading from the city i. In case infection affects all the cities output 0.

Example

Input:

1

6

5 10 15 20 25 30

1 3

2 3

3 4

4 5

4 6

Output:

6 6 6 2 6 5

MY C++ SOLUTION

#include <iostream>
#include <vector>
#include <list>
#include <stdio.h>
#include <algorithm>
using namespace std;

int main() {
    int t;
    scanf("%d", &t); //No. of test cases
    while(t--) {
        int n;
        scanf("%d", &n);
        vector<int> p(n);   //vector for storing population of each city
        for(int i = 0; i < n; i++)
            scanf("%d", &p[i]);

        vector<list<int> > graph(n); //vector of lists for storing connection between cities


        for(int i = 0; i < n-1; i++) { 
            int a, b;
            scanf("%d %d", &a, &b);
            graph[--a].push_back(--b);
            graph[b].push_back(a);
        }

        for(int i = 0; i < n; i++) {
            vector<int> temp = p;             //Temporary vector 

        /*All the infected cities are assigned a population
          of -1 so that they don't compete to become the largest capital*/

            temp[i] = -1;
            if(graph[i].size() == n-1) {//Printing "0" if all cities have connection with the infected city.
                cout<<"0 ";
                continue;
            }
            int s = graph[i].size();
            for(int j = 0; j < s; j++) {
                temp[graph[i].front()] = -1;
                graph[i].pop_front();
            }

            /*Finding max. population*/
            int maxindex = std::distance(temp.begin(), std::max_element(temp.begin(), temp.end()));

            printf("%d ", maxindex+1);
        }
        printf("\n");
    }
    return 0;
} 

The function max_element is making the time complexity quadratic. My solution is getting time limit exceeded for large inputs. Hence, my program needs improvement in time taken on execution. Please help. Thanks for your time.

Gyanshu
  • 1
  • 4
  • 1
    Please take the [Tour](https://stackoverflow.com/tour). Your question seems off-topic to me. Are you looking for a [Code Review](https://codereview.stackexchange.com/)? – Hermann Döppes Jan 09 '17 at 23:01
  • @Gyanshu You should edit your code to have the data hard-coded into your program. There is no need for `scanf` calls if what you posted is the test data. This allows others who are willing to help to easily copy and paste your code and run it without entering the data each and every time. – PaulMcKenzie Jan 09 '17 at 23:35
  • @Gyanshu Also, why so many loops to copy data? This: `for(int j = 0; j < n; j++) { temp[j] = p[j];}` is just this: `temp = p;`.without any `for` loop – PaulMcKenzie Jan 09 '17 at 23:40
  • @Gyanshu Also `maxindex = std::distance(temp.begin(), std::max_element(temp.begin(), temp.end());` -- no need for a loop to calculate the maxindex (and thus, `max`). – PaulMcKenzie Jan 09 '17 at 23:44
  • @PaulMcKenzie While both the things you mentioned will shorten my code a bit, but it won't affect the time or space taken by my code while execution. – Gyanshu Jan 10 '17 at 07:47
  • I don't understand why do stupid people downvote a question coming from a new guy even if it is following all the rules. The problem statement is clear. The solution is also pretty clear with comments. Just don't know why. – Gyanshu Jan 10 '17 at 07:54
  • @Gyanshu You are wrong about your code taking the same time. I don't know if it will fix your timeout issues, but writing for loops when you can simply call `=` is making things worse, not better. The `=` for vector is optimized for speed. The same thing with the algorithm functions such as `max_element`. The writers of the vector class and algorithms are some of the best C++ coders in the business, and they are striving to get the best performance out of the platform they're writing for. – PaulMcKenzie Jan 10 '17 at 08:12
  • Also, you have a nested `for` loop in your program. When you are writing a nested loop, you are practically begging for timeout errors to occur. A nested loop usually means that your solution is `O(n*n)`, and solutions with that big-O complexity are always "timeout causing" solutions. More than likely, there is another solution that is logarithmic (or even linear) in time complexity that can be used (but you have to find what it is). – PaulMcKenzie Jan 10 '17 at 08:18
  • @PaulMcKenzie My nested for loop is of the order `O(n)` because i am traversing every element of my vector of lists only once and its size is maximum `2*n-2`. – Gyanshu Jan 10 '17 at 08:26
  • You have an outer loop that has `n` iterations, You have an inner loop with `s` iterations. That is `O(n*s)`. Worse case is `O(n*n)` if `s` approaches `n`. What makes you believe that writing a nested for loop with these limits is not quadratic in complexity? – PaulMcKenzie Jan 10 '17 at 08:33
  • @PaulMcKenzie It is O(n). I can explain you with help of an example.Lets say there are 5 cities. The worst case will be when one city is connected to all the other cities. In that case, our vector of lists will look like :`graph[0] -> 1->2->3->4, graph[1]->1, graph[2]->1 and graph[3]->1. In this case the size of the vector of lists will be `4+1+1+1 = 7` which is `2.n-2`. So, through all the iteration we are only doing a max. of `2.n-2` iterations. Hope you got that. Or tell me if i'm wrong. – Gyanshu Jan 10 '17 at 08:37
  • No matter how much you want to explain it, look at the raw code -- you coded a nested for loop. This is undeniable. If `s` approaches `n`, the complexity is `n*n`. Complexity measures come into play when the data is large, not small like `5` . Imagine if it is 10,000 or 50,000, not 5. It's like trying to make a bubble sort linear, because you use a "trick" to stop the sort, even though the bubble sort is written using a nested loop. The sort is still n*n just for the reason it is coded using a nested loop. – PaulMcKenzie Jan 10 '17 at 08:44
  • @PaulMcKenzie Please take a look at my last comment. The difference here is the inner `s` can't approach `n`. The sum of all the inner `s`es in different iteration can approach `2.n`. Thats all. – Gyanshu Jan 10 '17 at 08:45
  • What are the dimensions of the graph? If the graph can be square or even close to square, sorry, but that solution you coded is (n*n) complexity,. A linear solution would almost always be acceptable. – PaulMcKenzie Jan 10 '17 at 08:49
  • @PaulMcKenzie That graph can't be square in any case or even close. Please look at my last 2 comments and read the question again, you'll get it. The solution is linear. The graph in solution contains a maximum of `2.n-2` elements which of order `n` not even close to `n^2`. – Gyanshu Jan 10 '17 at 08:51
  • Again, linear solutions are the best you can get. And why it can't be square? I can come up with values for `a` and `b` that can make the graph square. You need to tell us what the values of `a`, `b`, and `n` are for the test cases that fail. – PaulMcKenzie Jan 10 '17 at 08:56
  • @PaulMcKenzie Try to understand please. Look the total no. iterations here will be `s_1+s_2+...+s_n` Now the thing is `max(s_1+s_2+...+s_n) = 2.n-2`. Hence it is of the order `O(2n-2) = O(n)`. You can figure that it can't be square if you read the problem statement. `All of the cities are connected through 'n-1' roads that it's possible to travel between any two cities using those roads.` – Gyanshu Jan 10 '17 at 08:58
  • No, you are looping n times, and inside the loop, s times. It is that simple -- don't know how to explain it any simpler than that. If your solution was indeed linear, why the timeout issues? – PaulMcKenzie Jan 10 '17 at 09:01
  • @PaulMcKenzie Just leave it. I can't make you understand more. Damn it. Last try : **The 's' can't reach near 'n'. But its sum over all the iterations reach near `2.n` according to the problem statement.** – Gyanshu Jan 10 '17 at 09:04
  • Well, you explain why a "linear solution" is causing timeouts. If your solution is indeed linear, then complain to the online contest judges that their test is unfair. – PaulMcKenzie Jan 10 '17 at 09:05
  • @PaulMcKenzie Got it. The function max_element is taking linear time complexity not the loop you stated. Don't know how to improve that. – Gyanshu Jan 10 '17 at 09:07

2 Answers2

0

Because there is no information on what "bigger inputs" means I'm guessing it refers to having more cities. In that case, you are making a huge (nxn) graph array which will cause more memory to be hogged while at the same time being (mostly) empty as there are only n-1 roads. Consider connecting the cities with std::list and then look only for cities not in the same list as the infected city.

Kostas
  • 127
  • 5
  • While the graph takes more memory, it also gives O(1) access to know which cities will be infected by a particular city virus. In case of lists, the time complexity will be linear. – Gyanshu Jan 09 '17 at 22:56
  • 1
    @Gyanshu: Currently, you are going through every city to see if it's connected or not. Going through a list of the connected cities will take less time. – Nick Matteo Jan 09 '17 at 23:06
  • @Kundor You maybe right, but does it affect the time complexity because in the worst case the city which is infected might be connected to every other city. – Gyanshu Jan 09 '17 at 23:15
  • @Gyanshu: In which case, going through all n cities in the list of connected cities is the same as going through all n cities like you're already doing. – Nick Matteo Jan 09 '17 at 23:16
  • @Kundor Got it, you both are right. Lemme check if changing that solves my problem. – Gyanshu Jan 09 '17 at 23:17
  • @Kundor The catch here is that if one city is connected to every other city then the rest of the cities will be connected to only that city. So in that case i have to traverse a total of only n+1 positions but in case of graph i had to go traverse n^2 positions. – Gyanshu Jan 09 '17 at 23:20
  • The only thing used in the posted app that is an "array" is `std::vector`. Given that vector allocates its memory dynamically from the heap, I highly doubt it is the size of the input that is giving the SIGABRT. If anything, I'm more suspicious of the vector indices using `[ ]`. If the vector is accessed out-of-bounds, the behavior of the program is undefined. – PaulMcKenzie Jan 09 '17 at 23:31
  • Going through the code, I couldn't see any such error as there is only one common size, n. I could have missed something, but then the trial program would also fail randomly not only at large systems. There might be an extra issue of graph[i][j] being randomly initialized to 1, but this should give an error in the algorithm not SIGABRT. Finally, I don't know how large the systems get, but with 65535 cities, 4GB of RAM should be filled. – Kostas Jan 09 '17 at 23:55
  • I am editing my solution to have list instead of vector as suggested because it helped me pass 4 test cases. But i am still getting time limit exceeded in the last 2 cases in which inputs are really really large. Please help. – Gyanshu Jan 10 '17 at 07:28
0

Solved! The trick was to sort the population of cities beforehand.

#include <iostream>
#include <vector>
#include <list>
#include <stdio.h>
#include <algorithm>
using namespace std;
bool myfnc(pair<int, int> i, pair<int, int> j) {
    return i.first > j.first;
}
int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int n, d;
        scanf("%d", &n);
        vector<int> p(n);
        int m = 0, mi = 0;
        for(int i = 0; i < n; i++) {
            scanf("%d", &d);
            p[i] = d;
        }
        vector<pair<int, int> > p1(n);
        for(int i = 0; i < n; i++) {
            p1[i].first = p[i];
            p1[i].second = i;
        }
        sort(p1.begin(), p1.end(), myfnc);

        vector<vector<bool> > graph(n, vector<bool> (n));
        for(int i = 0; i < n-1; i++) {
            int a, b;
            scanf("%d %d", &a, &b);
            graph[--a][--b] = 1;
            graph[b][a] = 1;
            graph[i][i] = 1;
        }
        graph[n-1][n-1] = 1;
        for(int i = 0; i < n; i++) {
            int j;
            for(j = 0; j < n; j++) {
                if(graph[i][p1[j].second] == 0) {
                    printf("%d ", p1[j].second+1);
                    break;
                }
            }
            if(j == n)
                printf("0 ");
        }
        printf("\n");
    }
    return 0;
}
Gyanshu
  • 1
  • 4