题意:孩子们在幼儿园非常喜欢老虎抓小鸡的游戏。但是有一个比较大的问题:每一个人都想演老虎的角色。
因此老师提出一个建议:选举。每个孩子手里面有一些漂亮的手帕,如果他认为某个人适合老虎的角色,他就拿出一个手帕给他,也就是说得到手帕就是得到支持的一票。注意支持是可以传递的。最后得到支持票数最多的人将扮演老虎的角色。(注意:如果A赢得B的支持,A只能得到B的一票,不管B有多少票,既是说A = B得到的选票 + 1,A不能投自己一票)如果多个人获得同样多的票,我们称他们都是赢家。 例子:三个人 A,B,C。A拿一个手帕给B, B拿一个手帕给C, 因此 C得到2个手帕,C被选为扮演老虎。先输入一个测试样例数T,然后输入n 和 m,n是人数(0 ~ n - 1),下面是m行 A B (A!= B)代表A支持B。输出最大得票数,和得票者。
这题我做的时候求强连通分支、缩点都很顺利,后来还是WA了,后来看了别人的代码才发现我的问题:在计算每个点(已缩)的最大值除了问题。见下图.
缩完点有可能出现图中的情况(因为上图并不是强连通的,只是个弱连通,所以有可能出现),在我原来的程序中DFS计算点4的票数时会把点3 的贡献给忽略了,从而点5的值也就错了。正确的做法是按照上图建个逆图(边的方向相反,如下图),这样从逆图的根(准确来讲是入度为0的点,因为这样的点在图中可能不只一个)开始DFS计算根的值,就能方便正确地得到点5 的值了。
至于为什么要选择从入度为0的点开始DFS并比较这些点的值的大小(换句话说为什么答案一定出自这些点)?如果假设最大值存在于一个入度不为0的分量中,那么连接这个分量的 那个分量票数支持肯定大于这个分量,假设不成立。
逆向图DFS的伪代码:
void dfs(int u){ num[u]=n[u]; for each(u,v) in 逆向图 { dfs(v); num[u]+=num[v]; }}