Блог пользователя NeverSee

Автор NeverSee, история, 5 лет назад, По-английски

Have a DAG and we want that for each node v find the number of vertex that existence a path from v to that vertexes
for n <= 1e5

  • Проголосовать: нравится
  • -10
  • Проголосовать: не нравится

»
5 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

I think simple traversing can helpful.

const int MAX = 100 * 1000 + 11;
int arr[MAX]; //intial all nodes contain 0
vector<int > v[MAX]; // contain edges
void process(int node){
	if(v[node].size() == 0){
		arr[node] = 0;
		return;
	}
	for(int i = 0; i < v[node].size(); i++){
		process(v[node][i]);
		arr[node] += (1 + arr[v[node][i]]);
	}
}
  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    That is Good but the order is O(n^2);

    • »
      »
      »
      5 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Not really because you are using the adjacency-list representation of the graph.

      Actually the answer is just to run DFS/BFS on that node and see how many nodes are visited in the process.

      Complexity O(E + V)

      • »
        »
        »
        »
        5 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        That not for each vertex

        • »
          »
          »
          »
          »
          5 лет назад, # ^ |
            Проголосовать: нравится +2 Проголосовать: не нравится

          Then you can find the condensation graph into SCC and run DFS to find the answer recursively. Complexity doesn't change

    • »
      »
      »
      5 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

      I have modified the code to make it run in O(n)

      const int MAX = 100 * 1000 + 11;
      int arr[MAX]; //intial all nodes contain 0
      vector<int > v[MAX]; // contain edges
      void process(int node){
              if (arr[node]!=0) return ; //prevents re-calculations
      	if(v[node].size() == 0){
      		arr[node] = 0;
      		return;
      	}
      	for(int i = 0; i < v[node].size(); i++){
      		process(v[node][i]);
      		arr[node] += (1 + arr[v[node][i]]);
      	}
      }
      
  • »
    »
    5 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится +4 Проголосовать: не нравится

    Can we really compute the number of vertices that can be reached from vertex v with this algorithm?

    I think this graph is a counterexample.

    (UPD: Sorry, the number with the red color font actually should be 6)

»
5 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

You can use a bit-parallel strategy.

Assuming bit operations for one word is O(1), and let |word| the word-length of your machine, and then the time complexity would be O(NM/|word|). The memory complexity to store the reachability can be O(N*|word|) if you only care about the reachability from |word| vertices at the same time.

In other words, in today's 64-bit environment, it's nearly 64x faster than the naive algorithm to check the reachability from each vertex to all vertices one by one.