Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
1 2
2 1
2 3
Sample Output
1【数据范围】
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
10%的数据N<=20, M<=50
30%的数据N<=1000,M<=20000
70%的数据N<=5000,M<=50000
100%的数据N<=10000,M<=50000
1.找到所有强连通块
2.计算所有联通块的出度
3.如果有一个联通块出度为零,说明为最受欢迎的牛群
4.如果存在两个联通块出度为零,说明不存在最受欢迎的牛
2.计算所有联通块的出度
3.如果有一个联通块出度为零,说明为最受欢迎的牛群
4.如果存在两个联通块出度为零,说明不存在最受欢迎的牛
1 #include <cstdlib> 2 #include <iostream> 3 #include <fstream> 4 #include <cstring> 5 /* run this program using the console pauser or add your own getch, or input loop */ 6 7 using namespace std; 8 9 ifstream fin("popular.in"); 10 ofstream fout("popular.out"); 11 12 int cows=0,roads=0; 13 14 int head[10002]={0},cnt_lian=0; 15 struct lian{ 16 int to; 17 int next; 18 }; 19 lian liansi[50002]={0};//链式前向星 20 21 int top=0; 22 int stack[10002]={0}; 23 bool instack[10002]={0};//是否在栈里面 24 25 int cnt_dfn=0;//记录步数 26 int dfn[10002]={0}; 27 int low[10002]={0}; 28 29 30 31 int cnt_scc_node=0;//记录有几个联通块 32 int scc_node[10002]={0};//记录每个联通块里面有几个奶牛 33 int scc_belong[10002]={0};//记录每个奶牛属于几号联通块 34 35 bool cnt_chudu[10002]={0};//记录每个联通块是否有出度 36 37 void cun_lian(int a,int b);//存 链式前向星 38 void scc_meijv( );//枚举没有走到的点 39 void scc(int hao);//tarjan算法算联通块 40 41 void cun_lian(int a,int b){ 42 liansi[++cnt_lian].next=head[a]; 43 liansi[cnt_lian].to=b; 44 head[a]=cnt_lian; 45 return; 46 } 47 48 void scc_meijv(){ 49 for(int x=1;x<=cows;x++){ 50 if(dfn[x]==0)scc(x);//如果有一个点没走到,就去枚举 51 } 52 return; 53 } 54 55 void scc(int hao){ 56 cnt_dfn++; 57 dfn[hao]=cnt_dfn; 58 low[hao]=cnt_dfn;//low默认为此时走到的步数 59 60 stack[++top]=hao; 61 instack[hao]=true;//入栈 62 63 for(int x=head[hao];x!=-1;x=liansi[x].next){ 64 int dao=liansi[x].to; 65 if(dfn[dao]==0){//如果没有算过 66 scc(dao);//就去计算 67 low[hao]=min(low[hao],low[dao]); 68 } 69 else if (instack[dao]){//如果在栈中 70 low[hao] = min(low[hao], dfn[dao]); 71 } 72 } 73 74 if(dfn[hao]==low[hao]){//表示出现了一个联通块 75 cnt_scc_node++;//联通块个数加一 76 int ding=0; 77 do{ 78 ding=stack[top--]; 79 scc_belong[ding]=cnt_scc_node; 80 scc_node[cnt_scc_node]++; 81 instack[ding]=false;//一个一个出栈,并作好记录 82 }while(ding!=hao); 83 } 84 85 return; 86 } 87 88 int main(int argc, char *argv[]) { 89 fin>>cows>>roads; 90 91 memset(head,-1,sizeof(head)); 92 for(int x=1;x<=roads;x++){ 93 int a,b; 94 fin>>a>>b; 95 cun_lian(a,b); 96 } 97 98 99 scc_meijv(); 100 101 for(int x=1;x<=cows;x++){ 102 int size_x=scc_belong[x]; 103 for(int y=head[x];y!=-1;y=liansi[y].next){//搜索每一头奶牛的出度 104 if(cnt_chudu[size_x]==true)break;//如果这个奶牛所在的联通块已经有了出度,便可以不用计算. 105 int dao=liansi[y].to; 106 int size_y=scc_belong[dao]; 107 if(size_x!=size_y){//如果枚举的奶牛的出度所连的不是同一个联通块 108 cnt_chudu[size_x]=true; break;//表示这头奶油所在的联通块有了出度 109 } 110 } 111 } 112 113 int cnt_pop_scc=0;//记录出度为零的联通块 114 int cnt_pop_cow=0;//记录最受欢迎的牛的个数 115 for(int x=1;x<=cnt_scc_node;x++){//枚举每个联通块 116 if(cnt_chudu[x]==false){//如果有一个联通块出度为零 117 cnt_pop_scc++;//那么出度为零的联通块的个数加一 118 cnt_pop_cow+=scc_node[x];//加上里面所以奶牛 119 if(cnt_pop_scc>1){//当出度为零的联通块的个数大于一说明不存在最受欢迎的牛奶联通块 120 cnt_pop_cow=0; break;//最受欢迎的牛的个数为零 121 } 122 } 123 } 124 125 126 cout<<cnt_pop_cow; 127 fout<<cnt_pop_cow; 128 129 return 0; 130 } 131 132