强连通分量分解 -Popular Cows POJ - 2186 / The Cow Prom POJ - 3180 /Network of Schools POJ - 1236

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tawn0000/article/details/83018079

                                                强连通分量分解

强连通分量: 图中一个具有以下性质的子图,子图图每一点之间都能直接或间接到达,再加入一点后不再满足上一条性质

解决办法:两遍dfs,第一遍dfs后序遍历,将点存入vs中,然后利用vs,从后往前是跑反向dfs,并且拓扑标号,同一强连通分量标一个号。

模板:

int n,m;
vector <int> G[maxn];//正向邻接表
vector <int> rG[maxn];//反向邻接表
vector <int> vs;     //拓扑序存点
int cmp[maxn]; //标号
bool used[maxn];//


void dfs(int x)
{
  used[x] = true;
  for(int i = 0; i < G[x].size(); i++)
   if(!used[G[x][i]])  dfs(G[x][i]);
  vs.push_back(x);
}

void rdfs(int x, int k)
{
  used[x] = true;
  cmp[x] = k;
  for(int i = 0; i < rG[x].size(); i++)
    if(!used[rG[x][i]]) rdfs(rG[x][i],k);
}

int scc()
{
  memset(used, false , sizeof(used));
  vs.clear();
  for(int i = 1; i <= n; i++)
     if(!used[i]) dfs(i);
  memset(used, false ,sizeof(used));
  int k = 0;
  for(int i = vs.size()-1; i >= 0; i--)
     if(!used[vs[i]])  rdfs(vs[i],++k);
  return k;
}

                                             Popular Cows POJ - 2186

Total Submissions: 40716   Accepted: 16561

Description

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity.

强连通分量分解模板题

分析一下,可以发现,如果存在红牛,则必然是在用强连通分量分解后形成的DAG中的拓扑序的最后一点,如果这个提是由强连通分量分解而来,则这个点所代表的强连通分量的所有点都是红牛,并且同时如果这个DAG是不连通的,则说明没有红牛。

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 1e4+10;
const int maxm = 5e4+10;

int n,m;
vector <int> G[maxn];
vector <int> rG[maxn];
vector <int> vs;

bool used[maxn];
int cmp[maxn];


void dfs(int x)
{
  used[x] = true;
  for(int i = 0; i < G[x].size(); i++)
   if(!used[G[x][i]])  dfs(G[x][i]);
  vs.push_back(x);
}

void rdfs(int x, int k)
{
  used[x] = true;
  cmp[x] = k;
  for(int i = 0; i < rG[x].size(); i++)
    if(!used[rG[x][i]]) rdfs(rG[x][i],k);
}

int scc()
{
  memset(used, false , sizeof(used));
  vs.clear();
  for(int i = 1; i <= n; i++)
     if(!used[i]) dfs(i);
  memset(used, false ,sizeof(used));
  int k = 0;
  for(int i = vs.size()-1; i >= 0; i--)
     if(!used[vs[i]])  rdfs(vs[i],++k);
  return k;
}

int main()
{
   scanf("%d%d",&n,&m);
   for(int i = 0; i < m; i++)
   {
     int u,v;
     scanf("%d%d",&u,&v);
     G[u].push_back(v);
     rG[v].push_back(u);
   }
   int sum = scc();
   int ans = 0, num = 0;
   for(int i = 1; i <= n; i++)
     if(cmp[i] == sum) ans = i,num++;
   memset(used,false,sizeof(used));
   rdfs(ans,0);
   for(int i = 1; i <= n; i++)
     if(!used[i]) {num = 0;break;}
   printf("%d\n",num);
   return 0;
}

                                          The Cow Prom POJ - 3180

Language:

The Cow Prom

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2735   Accepted: 1606

Description

The N (2 <= N <= 10,000) cows are so excited: it's prom night! They are dressed in their finest gowns, complete with corsages and new shoes. They know that tonight they will each try to perform the Round Dance.

Only cows can perform the Round Dance which requires a set of ropes and a circular stock tank. To begin, the cows line up around a circular stock tank and number themselves in clockwise order consecutively from 1..N. Each cow faces the tank so she can see the other dancers.

They then acquire a total of M (2 <= M <= 50,000) ropes all of which are distributed to the cows who hold them in their hooves. Each cow hopes to be given one or more ropes to hold in both her left and right hooves; some cows might be disappointed.

For the Round Dance to succeed for any given cow (say, Bessie), the ropes that she holds must be configured just right. To know if Bessie's dance is successful, one must examine the set of cows holding the other ends of her ropes (if she has any), along with the cows holding the other ends of any ropes they hold, etc. When Bessie dances clockwise around the tank, she must instantly pull all the other cows in her group around clockwise, too. Likewise,
if she dances the other way, she must instantly pull the entire group counterclockwise (anti-clockwise in British English).

Of course, if the ropes are not properly distributed then a set of cows might not form a proper dance group and thus can not succeed at the Round Dance. One way this happens is when only one rope connects two cows. One cow could pull the other in one direction, but could not pull the other direction (since pushing ropes is well-known to be fruitless). Note that the cows must Dance in lock-step: a dangling cow (perhaps with just one rope) that is eventually pulled along disqualifies a group from properly performing the Round Dance since she is not immediately pulled into lockstep with the rest.

Given the ropes and their distribution to cows, how many groups of cows can properly perform the Round Dance? Note that a set of ropes and cows might wrap many times around the stock tank.

Input

Line 1: Two space-separated integers: N and M

Lines 2..M+1: Each line contains two space-separated integers A and B that describe a rope from cow A to cow B in the clockwise direction.

Output

Line 1: A single line with a single integer that is the number of groups successfully dancing the Round Dance.

Sample Input

5 4
2 4
3 5
1 2
4 1

Sample Output

1

Hint

Explanation of the sample:

ASCII art for Round Dancing is challenging. Nevertheless, here is a representation of the cows around the stock tank:
       _1___

      /**** \

   5 /****** 2

  / /**TANK**|

  \ \********/

   \ \******/  3

    \ 4____/  /

     \_______/
Cows 1, 2, and 4 are properly connected and form a complete Round Dance group. Cows 3 and 5 don't have the second rope they'd need to be able to pull both ways, thus they can not properly perform the Round Dance.

Source

USACO 2006 January Silver

强连通分量分解模板题

题目是求强连通分量个数,所以只有把模板变成统计得到的DAG中点是由缩点而来的点的个数

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 1e4+10;
const int maxm = 5e4+10;

int n,m;
vector <int> G[maxn];
vector <int> rG[maxn];
vector <int> vs;

bool used[maxn];
int cmp[maxn];


void dfs(int x)
{
  used[x] = true;
  for(int i = 0; i < G[x].size(); i++)
   if(!used[G[x][i]])  dfs(G[x][i]);
  vs.push_back(x);
}

void rdfs(int x, int k, int &sum)
{
  sum ++;
  used[x] = true;
  cmp[x] = k;
  for(int i = 0; i < rG[x].size(); i++)
    if(!used[rG[x][i]]) rdfs(rG[x][i],k,sum);
}

int scc()
{
  memset(used, false , sizeof(used));
  vs.clear();
  for(int i = 1; i <= n; i++)
     if(!used[i]) dfs(i);
  memset(used, false ,sizeof(used));
  int k = 0,res = 0;
  for(int i = vs.size()-1; i >= 0; i--)
     {
       int sum = 0;
       if(!used[vs[i]])  rdfs(vs[i],++k,sum);
       if(sum > 1) res++;
     }
  return res;
}

int main()
{
   scanf("%d%d",&n,&m);
   for(int i = 0; i < m; i++)
   {
     int u,v;
     scanf("%d%d",&u,&v);
     G[u].push_back(v);
     rG[v].push_back(u);
   }
   int ans = scc();
   printf("%d\n",ans);
   return 0;
}

                                        Network of Schools POJ - 1236

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 24311   Accepted: 9637

Description

A number of schools are connected to a computer network. Agreements have been developed among those schools: each school maintains a list of schools to which it distributes software (the “receiving schools”). Note that if B is in the distribution list of school A, then A does not necessarily appear in the list of school B
You are to write a program that computes the minimal number of schools that must receive a copy of the new software in order for the software to reach all schools in the network according to the agreement (Subtask A). As a further task, we want to ensure that by sending the copy of new software to an arbitrary school, this software will reach all schools in the network. To achieve this goal we may have to extend the lists of receivers by new members. Compute the minimal number of extensions that have to be made so that whatever school we send the new software to, it will reach all other schools (Subtask B). One extension means introducing one new member into the list of receivers of one school.

Input

The first line contains an integer N: the number of schools in the network (2 <= N <= 100). The schools are identified by the first N positive integers. Each of the next N lines describes a list of receivers. The line i+1 contains the identifiers of the receivers of school i. Each list ends with a 0. An empty list contains a 0 alone in the line.

Output

Your program should write two lines to the standard output. The first line should contain one positive integer: the solution of subtask A. The second line should contain the solution of subtask B.

Sample Input

5
2 4 3 0
4 5 0
0
0
1 0

Sample Output

1
2

Source

IOI 1996

题目有点难懂,意思大概是:

给你一个图,

1.问你这个图至少需要取几个点,可以将从这个图从这几个点遍历到整张图

2.问你这个图至少需要加几条边,可以取任意一个节点将整张图遍历到。

首先利用强联通分量将图变成一个DAG图,即有向无环图,

至少需要取的点数是该图中入度为0的点的数目

至少需要取的边数是max(入度为0的点的数目,出度为0的点的数目)

证明的话自己画个图理解一下~V~

需要特判这个DAG只有一个点的情况,答案是0不是1

#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int maxn = 100+10;
const int maxm = 5e4+10;

int n,m;
vector <int> G[maxn];//正向邻接表
vector <int> rG[maxn];//反向邻接表
vector <int> vs;     //拓扑序存点
int cmp[maxn]; //标号
bool used[maxn];//

void dfs(int x)
{
  used[x] = true;
  for(int i = 0; i < G[x].size(); i++)
   if(!used[G[x][i]]) dfs(G[x][i]);
  vs.push_back(x);
}

void rdfs(int x, int k)
{
  used[x] = true;
  for(int i = 0; i < rG[x].size(); i++)
   if(!used[rG[x][i]]) rdfs(rG[x][i],k);
  cmp[x] = k;
}

int in[maxn];
int out[maxn];

void scc()
{
  memset(used,false,sizeof(used));
  for(int i = 1; i <= n; i++)
    if(!used[i]) dfs(i);
  int tot = 0;
  memset(used,false,sizeof(used));
  for(int i = vs.size()-1; i >= 0; i--)
    if(!used[vs[i]]) rdfs(vs[i],++tot);
  memset(in,0,sizeof(in));
  memset(out,0,sizeof(out));
  for(int i = 1; i <= n; i++)
    for(int j = 0; j < G[i].size(); j++)
    {
           int u = cmp[i], v = cmp[G[i][j]];
           if(u != v) {out[u]++;in[v]++;}
    }
  //cout << tot << endl;
  int sum1 = 0, sum2 = 0, sum3 = 0;
  for(int i = 1; i <= tot; i++)
  {
    if(in[i]  == 0) sum1++;
    if(out[i] == 0) sum2++;
  }
  printf("%d\n%d\n",sum1,tot == 1 ? 0 : max(sum1,sum2));
}

int main()
{
   scanf("%d",&n);
   int v;
   for(int i = 1; i <= n; i++)
     while(scanf("%d",&v) && v)
     {
       G[i].push_back(v);
       rG[v].push_back(i);
     }

   scc();
   return 0;
}

猜你喜欢

转载自blog.csdn.net/Tawn0000/article/details/83018079