ural Team building(强连通分支)
寒假集训已经开始几天了,直到搬完宿舍才感觉安定下来,开始静下心了认真学习算法,这几天心无旁骛的学习,效率自然提了上来,感觉以前不熟的算法或是没想透的地方在做过两道题后都可以理解了,好好利用这十几天的集训,提高一下自己的水平吧~
题意:IT公司有n名程序员,他们都认为自己是最优秀或第二优秀的程序员,公司的管理者打算将他们分到不同的开发小组里,分配的条件如下:
(1、任意选出一名未被分配的程序员,然后给他建立一个开发小组,他作为当前程序员。
(2、如果在他的同事中,他认为这个人比他优秀,那么这个比他优秀的人就不能被分配到其他小组,只能分配到这个小组,成为这个小组的当前程序员。
题目要求这n名程序员最多和最少可以分配到多少个开发小组中。
思路:如果A认为B比他强,那么A到B有一条有向边,如果一个人的入度为0,就是没有人认为他比他强,那么就从这个人搜起,依次往下,直到搜到一个已经搜过的。如果这个搜过的人是这个小组的,那么这是一个环,除了环里的,其他的都可以自己一个人建立一个开发小组,也可以与环里的人在同一个小组。如果搜过的这个人不是这个小组的,那么所有搜过的人都可以自己建立一个小组。
代码:
View Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <queue> #include <math.h> #include <map> #include <queue> #include <stack> #include <vector> #define N 100003 using namespace std ; int nexts[N] , vist[N] , cnt[N] ; int n , in[N] ; int dfs( int x ) { int flag = x ; int tot = 0 ; while ( !vist[x] ) { vist[x] = flag ; cnt[x] = tot++ ; if( vist[nexts[x]] ) { if ( vist[nexts[x]] == flag ) { return cnt[nexts[x]] ; } else { return ( tot - 1 ) ; } } x = nexts[x] ; } } int main() { int i , min_s , max_s ; while ( scanf ( "%d" , &n ) != EOF ) { memset( in , 0 , sizeof ( in )) ; for ( i = 1 ; i <= n ; i++ ) { scanf ( "%d" , &nexts[i] ) ; in[nexts[i]]++ ; } memset( vist , 0 , sizeof ( vist )) ; memset( cnt , 0 , sizeof ( cnt )) ; min_s = 0 ; max_s = 0 ; for ( i = 1 ; i <= n ; i++ ) { if ( in[i] == 0 ) { min_s++ ; max_s += dfs( i ) + 1 ; } } for ( i = 1 ; i <= n ; i++ ) { if ( !vist[i] ) { min_s++ ; max_s += dfs( i ) + 1 ; } } printf ( "%d %d\n" , min_s , max_s ) ; } return 0 ; }