题目链接: Network of Schools
题意
本题就是说给你一个有向图,然后告诉你每个点与哪些点相连,然后问你需要多少个点才能从这个点出发遍历另外的全部的点。需要增加多少条有向路,才能使得两个点之间可以任意联通成为一个强联通图。
思路
利用tarjan缩点之后,我们可以很容易求出来有n个点的入度为0,有m个点的出度为0.(这些点是缩后的点)那么需要的点数为n,需要增加的有向路的条数为max(n,m)。
#include <iostream>
#include <algorithm>
#include <string>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=101;
vector<int>G[maxn];
int scc,index,top,N,In,belong[101],Out,dfn[101],low[101],Stack[101],vis[101],in[101],out[101]; //scc记录强联通图的个数。
void tarjan(int x)
{
int i, v;
dfn[x] = low[x] = ++index;
vis[x] = 1;
Stack[++top] = x;
for( i = 0 ; i < G[x].size() ; i++)
{
v = G[x][i];
if(!dfn[v])
{
tarjan(v);
low[x] = min(low[x] , low[v]);
}
else if(vis[v])
low[x] = min(low[x] , dfn[v]);
}
if(dfn[x] == low[x])
{
scc++;
do{
v = Stack[top--];
vis[v] = 0;
belong[v] = scc;
}while(v != x);
}
}
void unit()
{
memset(vis , 0 ,sizeof( vis));
memset(dfn, 0 , sizeof(dfn));
memset(low , 0 , sizeof(low));
memset(belong , 0 ,sizeof(belong));
memset(in , 0 , sizeof(in));
memset(out , 0 , sizeof(out));
}
void solve()
{
int i , j , v;
for(i = 1 ; i <= N ; i ++)
for(j = 0 ;j < G[i].size() ; j++)
{
v=G[i][j];
if(belong[i] != belong[v])
{
out[belong[i]]++;
in[belong[v]]++;
}
}
for(i = 1 ; i <= scc ; i++)
{
if(!in[i]) In++;
if(!out[i]) Out++;
}
if(scc == 1 )
{
cout << 1 <<endl;
cout << 0 <<endl;
}
else
{
cout << In << endl;
cout << max(In , Out) << endl;
}
}
int main()
{
int i , A;
cin >> N;
for(i = 1 ;i <= N ; i++)
{
do{
cin >> A;
if(A)
G[i].push_back(A);
}
while(A != 0);
}
scc = 0,index = 0,top = 0,In = 0,Out = 0;
unit();
for(i = 1 ; i <= N; i++)
if(!dfn[i])
tarjan(i);
solve();
}
题目链接: Popular Cows
题意
就是说给你什么牛喜欢什么牛,比如说A B就是A牛喜欢B牛,然后如果A牛喜欢B牛,B牛喜欢C牛,那么A牛喜欢C牛,在这样的条件下,问有多少头牛被所有的牛喜欢。
思路
依然是tarjan缩点,把强联通子图缩完后,我们看的是有多少个点的出度为0,如果有大于等于两个点的出度为0,那就说明没有牛符合条件。否则如果只有一个点符合出度为0,那么答案就是这个点所包含的牛的头数。
#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=10001;
vector<int>G[maxn];
int Count[maxn],Out,vis[maxn],Stack[maxn],DFN[maxn],low[maxn],belong[maxn],in[maxn],out[maxn];
int N,M,top,scc,counter,counter1,index,In;
void tarjan(int x)
{
int i,v;
vis[x] = 1;
Stack[++top] = x;
DFN[x] = low[x] = ++index;
for(i = 0 ; i < G[x].size() ; i++)
{
int v=G[x][i];
if(!DFN[v])
{
tarjan(v);
low[x] = min (low[x],low[v]);
}
else if(vis[v])
low[x]=min (low[x] ,low[v]);
}
if(DFN[x] == low[x])
{
scc++;
Count[scc] = 0;
do{
v = Stack[top--];
vis[v] = 0;
belong[v] = scc;
Count[scc]++;
}while(x != v);
}
}
void unit()
{
int i;
for(i =0 ; i <= N ; i ++)
{
in[i] = 0;
out[i] = 0;
DFN[i] = 0;
low[i] = 0;
belong[i] = 0;
Stack[i] = 0;
vis[i]=0;
}
}
void solve()
{
int i,v,j;
unit();
for(i = 1 ;i <= N ;i++)
{
if(!DFN[i])
tarjan(i);
}
for( i = 1 ; i <= N ; i++)
{
for(j = 0 ; j < G[i].size() ; j++)
{
v = G[i][j];
if(belong[i] != belong[v])
{
in[belong[v]]++;
out[belong[i]]++;
}
}
}
for(i = 1; i <= scc ; i ++)
{
if(out[i] == 0)
{
counter+=Count[i];
counter1++;
}
}
if(counter1 >= 2)
cout << 0 << endl;
else
cout << counter <<endl;
}
int main()
{
int i ,A,B;
while(scanf("%d %d",&N,&M)!=EOF)
{
top = 0,scc = 0,counter = 0,index = 0,In = 0,Out = 0 , counter1 = 0;
for(i = 1 ; i <= M ; i++)
{
cin >> A >> B;
G[A].push_back(B);
}
solve();
}
}
题目链接: Going from u to v or from v to u?
题意
就是给你一个有向图问你是否其中两点都是连通的(x到y是通路 或者y到x是通路都行)
思路
tarjan缩点后,我们看看最终的图是不是一个长链,如果不是就是No,我这里给的是拓扑排序,当然其实可以直接判断顶点出度=1,末点入度=1,其他点入度=出度=1,只有满足这个才符合条件。
#include <iostream>
#include <algorithm>
#include <string>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 1010;
int DFN[maxn],low[maxn],in[maxn],vis[maxn],Stack[maxn],out[maxn],belong[maxn];
vector<int>G[maxn];
vector<int>V[maxn];
int top,index,scc,In,Out,N,M;
void tarjan(int x)
{
int i,v;
vis[x] = 1;
Stack[++top] = x;
DFN[x] = low[x] = ++index;
for(i = 0 ; i < G[x].size(); i++)
{
v = G[x][i];
if(!DFN[v])
{
tarjan(v);
low[x] = min(low[x],low[v]);
}
else if(vis[v])
low[x] = min(low[x],low[v]);
}
if(DFN[x] == low[x])
{
scc++;
do{
v = Stack[top--];
vis[v] = 0;
belong[v] = scc;
}while(x != v);
}
}
void unit()
{
int i;
for( i = 0; i <= N ;i ++)
{
DFN[i] = 0;
belong[i] = 0;
in[i] = 0;
out[i] = 0;
low[i] = 0;
vis[i] = 0;
Stack[i] = 0;
}
}
int toposort()
{
int ans,i,v,u;
queue<int>Q;
for(i = 1 ;i <= scc ; i++)
{
if(!in[i])
Q.push(i);
}
while(!Q.empty())
{
ans = 0;
u=Q.front();
Q.pop();
for(i = 0 ;i < V[u].size() ;i++)
{
v = V[u][i];
in[v]--;
if(!in[v])
{
ans++;
Q.push(v);
}
}
if(ans > 1)
return 0;
}
return 1;
}
void solve()
{
int i,j,v;
unit();
for( i = 1 ; i <= N ;i++)
{
if(!DFN[i])
tarjan(i);
}
for( i = 1 ;i <= N ;i++)
{
for(j = 0 ; j < G[i].size() ;j++)
{
v = G[i][j];
if(belong[i] != belong[v])
{
out[belong[i]]++;
in[belong[v]]++;
V[belong[i]].push_back(belong[v]);
}
}
}
for( i = 1 ;i <= scc ; i++)
{
if(!in[i]) In++;
}
if(In > 1)
cout << "No" << endl;
else
{
if(toposort())
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
int main()
{
int T ,i, A, B;
cin.tie(0);
ios::sync_with_stdio(0);
cin >> T;
while( T--)
{
cin >> N >> M;
for( i = 1 ; i <= N ; i++)
{
G[i].clear();
V[i].clear();
}
for( i = 1 ; i <= M ; i++)
{
cin >> A >> B;
G[A].push_back(B);
}
top = 0,index = 0,scc = 0,In = 0,Out = 0;
solve();
}
}