牛奶生意正红红火火!
农夫约翰的牛奶加工厂内有 个加工站,编号为
,以及
条通道,每条连接某两个加工站。(通道建设很昂贵,所以约翰选择使用了最小数量的通道,使得从每个加工站出发都可以到达所有其他加工站)。
为了创新和提升效率,约翰在每条通道上安装了传送带。
不幸的是,当他意识到传送带是单向的已经太晚了,现在每条通道只能沿着一个方向通行了!
所以现在的情况不再是从每个加工站出发都能够到达其他加工站了。
然而,约翰认为事情可能还不算完全失败,只要至少还存在一个加工站 满足从其他每个加工站出发都可以到达加工站
。
注意从其他任意一个加工站 前往加工站
可能会经过
和
之间的一些中间站点。
请帮助约翰求出是否存在这样的加工站 。
输入格式
输入的第一行包含一个整数 ,为加工站的数量。
以下 行每行包含两个空格分隔的整数
和
,满足
以及
。
这表示有一条从加工站 向加工站
移动的传送带,仅允许沿从
到
的方向移动。
输出格式
如果存在加工站 满足可以从任意其他加工站出发都可以到达加工站
,输出最小的满足条件的
。
否则,输出 。
数据范围
输入样例:
3
1 2
3 2
输出样例:
2
解法一:拓扑排序
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;
}
解法二:弗洛伊德传递闭包
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
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;
}