基本思路:若i能到k,k能到j,则i一定能到达j。
利用Floyd传递闭包,求解所有点互相到达的情况,1表示可以,0表示不可以。
最后for循环1~n求出对于第i个点有多少个点能够到达它,如果等于n-1就直接输出这个i,退出循环即可。
思路很简单,代码实现也是不会太难。
hh,求个赞!有不懂的可以留言哦~
#include<bits/stdc++.h>
using namespace std;
int n, d[110][110], ans;
int main(){
scanf("%d", &n);
int u, v;
for (int i = 1; i < n; i++) scanf("%d%d", &u, &v), d[u][v] = 1;
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) d[i][j] |= d[i][k] & d[k][j];
for (int i = 1; i <= n; i++) {
int cnt = 0;
for(int j = 1;j <= n; j++) if(d[j][i]) cnt++;
if(cnt == n - 1) {ans = i; break;}
}
if (ans) printf("%d", ans);
else puts("-1");
return 0;
}
这个题可以用拓扑排序耶!
大佬能找份写的比较好的拓扑排序的资料吗,我还不知道拓扑排序是什么欸哈哈哈(我是不是很菜)
加油!
我拓扑排序是跟y总在算法基础课学的,刚在网上找了一篇还不错的文章:https://zhuanlan.zhihu.com/p/260112913
Thanks
想问一下,三个嵌套的for循环为什么不能是i,j,k呀?我这么写的时候由一组数据测试不通过
嗯,这也是许多编程的人错的地方。
Floyd它本质上是动态规划,推荐阅读一下李煜东巨佬的《算法竞赛进阶指南》,里面有详细的说明。
有测试数据不通过是正常的,因为我的代码中第一层k循环指的是阶段,也就是说d[k][i][j]是指i到j经过k的一条最短路径的长度。知道k是阶段整个就好理解了,那么k一定是第一层循环。
如果是i,j,k就不对了,不懂的话还是建议去发在问答区或者是问y总,当然看看《算法竞赛进阶指南》也可以
好的,感谢大佬
刚找到了《算法竞赛进阶指南》的在线阅读版本,免费的,给你看一下
http://jxz1.j9p.com/pc/sdgfdhgfhg.pdf
如果没有买的话看链接也行
啊啊啊太感谢了!
理论上是枚举中转点k,然后才能枚举起点和终点
(我好歹上过$J$组特训,还是有点基础的)嗯嗯,就是这样
请问d[i][j] |= d[i][k] & d[k][j]这句怎么操作的,我好像语法不太熟
好的,我写一下,请稍等
中间那个
&
的意思是且,这您应该知道吧,就是两个同时是1结果才是1,只要有一个是0结果就是0。所以
d[i][k] & d[k][j]
的意思就是说i到k有一条路径并且k到j有一条路径,才返回1,否则返回值0。然后前面还有一个
d[i][j] |=
,那个|
是或运算,就是说如果两个值有一个是1返回就为1,如果都是1也返回1。然而如果是两个数都是0的话就返回0。d[i][j] |= d[i][k] & d[k][j]
这句可以转化成:d[i][j] = d[i][j] | (d[i][k] & d[k][j])
,也就是说只要d[i][j]
和d[i][k] & d[k][j]
中有一个值为1,则d[i][j]
赋值为1,否则为0。还可以用if语句写,我等下留言
用if语句的话会比较好理解一些
if(d[i][k] && d[k][j]) d[i][j] = 1;
比较直观
明白了,谢谢大佬