POJ

来源:互联网 发布:软件外包管理 编辑:程序博客网 时间:2024/05/18 00:17

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is 
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow. 
Input
* Line 1: Two space-separated integers, N and M 

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular. 
Output
* Line 1: A single integer that is the number of cows who are considered popular by every other cow. 
Sample Input
3 31 22 12 3
Sample Output
1
Hint
Cow 3 is the only cow of high popularity. 


题意: 输入n,m, n为有n头牛,m为有m中关系,下面有m行,每行有两个数,a,b,表示 b 受 a 欢迎; 若a欢迎b,b欢迎c,那么a也欢迎c,求,有几只牛除自身外受全部的牛欢迎;

强连通分量:有向图中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,两个定点形成互达,则称两个顶点强连通(strongly connected),强连通分量,可能是个圆形结构,也有可能是网状结构,一定要记住还有网状结构;

思路: 先用 tarjan 算法,求出相互受欢迎的,相互受欢迎的就是一个强连通分量,再让强连通分量进行缩点;求出缩点后的树(图),出度为0(叶子)的节点个数;

代码:

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;#include<stack>#include<vector>#define Max 10100vector<int >v[Max];int n,m;int dfn[Max];   // 时间戳int low[Max];   //  为i或i的子树能够追溯到的最早的栈中节点的次序号int instack[Max]; // 判断是不是在栈中,为了避免重复int color[Max]; // 染色 强连通分量,为了进行缩点;int dfn_num;  //  为每一个节点加上时间戳int color_num;  //  强连通分量的数目stack<int > s;void init(){int i;for(i=0;i<=n;i++)v[i].clear();memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));memset(instack,0,sizeof(instack));memset(color,0,sizeof(color));}void Tarjan(int x)    //  tarjan 算法 {low[x] = dfn[x] = dfn_num++;instack[x] = 1;s.push(x);int i;for(i = 0;i<v[x].size();i++){int k = v[x][i]; if(!dfn[k]){Tarjan(k);low[x] = min(low[x],low[k]);}else if(instack[k]){low[x] = min(low[x],dfn[k]);}}if(dfn[x] == low[x]){instack[x]  = 0;color[x] = ++color_num;int t;do{t = s.top();s.pop();instack[t] = 0;color[t] = color_num;//if(t!=x)printf("%d ",t);}while(t!=x);//printf("%d\n",x);}}int hhh(){int i,j;int num[Max];  // 每个强连通分量中有多少节点(原图,未经缩点之前的图)int out[Max]; //每一个经缩点之后的节点(每个强连通分量)的出度;memset(num,0,sizeof(num));memset(out,0,sizeof(out));for(i=1;i<=n;i++){num[color[i]]++;for(j=0;j<v[i].size();j++){int k=v[i][j];if(color[i]!=color[k])out[color[i]]++;}}int con=0,t;for(i=1;i<=color_num;i++){if(out[i]==0){con++;t=i;}}return (con==1)?num[t]:0;  // 这个信息量很大,一个图经缩点之后一定是树,但这个首先只能是一个树,//若是两个树或多个树,经缩点之后的图,出度为0的节点数一定会大于等于2;// 若是一颗树,那么经缩点之后的树,只能有一个叶子,//若多个叶子,这个多个叶子谁也不欢迎谁,那么没有人会是最受欢迎的人;}int main(){int i,j;while(~scanf("%d%d",&n,&m)){init();int x,y;for(i=0;i<m;i++){scanf("%d%d",&x,&y);v[x].push_back(y);//v[y].push_back(x);}dfn_num = 1;color_num = 0;for(i=1;i<=n;i++)if(!dfn[i])Tarjan(i);printf("%d\n",hhh());}return 0;}


原创粉丝点击