牛奶生意正红红火火!

农夫约翰的牛奶加工厂内有 牛奶工厂(寒假每日一题 34)_拓扑排序 个加工站,编号为 牛奶工厂(寒假每日一题 34)_i++_02,以及 牛奶工厂(寒假每日一题 34)_思维题_03 条通道,每条连接某两个加工站。(通道建设很昂贵,所以约翰选择使用了最小数量的通道,使得从每个加工站出发都可以到达所有其他加工站)。

为了创新和提升效率,约翰在每条通道上安装了传送带。

不幸的是,当他意识到传送带是单向的已经太晚了,现在每条通道只能沿着一个方向通行了!

所以现在的情况不再是从每个加工站出发都能够到达其他加工站了。

然而,约翰认为事情可能还不算完全失败,只要至少还存在一个加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_04 满足从其他每个加工站出发都可以到达加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_04

注意从其他任意一个加工站 牛奶工厂(寒假每日一题 34)_算法_06 前往加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_04 可能会经过 牛奶工厂(寒假每日一题 34)_拓扑排序_04牛奶工厂(寒假每日一题 34)_算法_06 之间的一些中间站点。

请帮助约翰求出是否存在这样的加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_04

输入格式
输入的第一行包含一个整数 牛奶工厂(寒假每日一题 34)_拓扑排序,为加工站的数量。

以下 牛奶工厂(寒假每日一题 34)_思维题_03 行每行包含两个空格分隔的整数 牛奶工厂(寒假每日一题 34)_算法_13牛奶工厂(寒假每日一题 34)_拓扑排序_14,满足 牛奶工厂(寒假每日一题 34)_思维题_15 以及 牛奶工厂(寒假每日一题 34)_算法_16

这表示有一条从加工站 牛奶工厂(寒假每日一题 34)_算法_13 向加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_14 移动的传送带,仅允许沿从 牛奶工厂(寒假每日一题 34)_算法_13牛奶工厂(寒假每日一题 34)_拓扑排序_14 的方向移动。

输出格式
如果存在加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_04 满足可以从任意其他加工站出发都可以到达加工站 牛奶工厂(寒假每日一题 34)_拓扑排序_04,输出最小的满足条件的 牛奶工厂(寒假每日一题 34)_拓扑排序_04

否则,输出 牛奶工厂(寒假每日一题 34)_拓扑排序_24

数据范围
牛奶工厂(寒假每日一题 34)_i++_25

输入样例:

3
1 2
3 2

输出样例:

2


解法一:拓扑排序

#include<iostream>
#include<cstring>

using namespace std;

const int N = 110;

int h[N], ne[N], e[N], idx;
int n, d[N]; // 入度
int q[N]; // queue

void add(int a, int b){
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

bool topsort(){

int hh = 0, tt = -1;
for(int i = 1; i <= n; i++){
if(!d[i]) q[++tt] = i;
}

while(hh <= tt){

int u = q[hh++];
if(h[u] == -1 && hh != n) return false;
for(int i = h[u]; ~i; i = ne[i]){
int j = e[i];
d[j]--;
if(!d[j]) q[++tt] = j;
}
}

return hh == n;
}

int main(){

memset(h, -1, sizeof h);

scanf("%d", &n);

int a, b;
for(int i = 0; i < n; i++){

scanf("%d%d", &a, &b);
add(a, b);
d[b]++;
}

if(!topsort()) puts("-1");
else printf("%d\n", q[n - 1]);

return 0;
}

解法二:弗洛伊德传递闭包

#include<iostream>

using namespace std;

const int N = 110;

int n;
int g[N][N];

int main(){

cin >> n;

for(int i = 1; i <= n; i++) g[i][i] = 1;

for(int i = 0; i < n - 1; i++){

int a, b;
cin >> a >> b;
g[a][b] = 1;
}

for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(g[i][k] && g[k][j])
g[i][j] = 1;

for(int i = 1; i <= n; i++){

bool flag = true;
for(int j = 1; j <= n; j++){
if(!g[j][i]){
flag = false;
break;
}
}
if(flag) {
cout << i << endl;
return 0;
}
}

puts("-1");

return 0;
}

解法三:利用性质

​只能有一个点的出度为0​

#include<iostream>

using namespace std;

const int N = 110;

int n;
int d[N];

int main(){

scanf("%d", &n);

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

int cnt = 0, id;
for(int i = 1; i <= n; i++){
if(!d[i]){
cnt++;
id = i;
}
}

if(cnt == 1) printf("%d\n", id);
else puts("-1");

return 0;
}