程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> poj Popular Cows(tarjan +縮點)

poj Popular Cows(tarjan +縮點)

編輯:關於C++

Language: Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 24384 Accepted: 10007

Description

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 3
1 2
2 1
2 3

Sample Output

1

Hint

Cow 3 is the only cow of high popularity.

Source

USACO 2003 Fall

題意: n頭牛相互羨慕,可以傳遞羨慕,問被所有牛羨慕的牛的最大數目


思路:

tarjan縮點,把不同的點規劃到一個強聯通分支,最後判斷強連通分支出度為0的點是否唯一,唯一則有解,答案是該強連通分支的點的數目,否者無解


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include


#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define MID(x,y) ((x+y)>>1)

#define eps 1e-8
typedef __int64 ll;

#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define bug         pf("Hi\n")

using namespace std;

#define N 10024

int head[N],low[N],time[N],e_num,tim_num;
int n,m,ans,instack[N],vis[N],type[N],out[N];

struct stud{
  int to,next;
}e[N*10];

stackq;

inline void add(int u,int v)
{
    e[e_num].to=v;
    e[e_num].next=head[u];
    head[u]=e_num++;
}

void tarjan(int x)
{
    int i,j;
    q.push(x);
    instack[x]=1;

    time[x]=low[x]=++tim_num;

    for(i=head[x];i!=-1;i=e[i].next)
    {
        int to=e[i].to;
        if(time[to]==0)
        {
            tarjan(to);
            if(low[x]>low[to]) low[x]=low[to];
        }
        else
            if(instack[to]&&low[x]>time[to])
                low[x]=time[to];
    }

    if(low[x]==time[x])
    {
        ans++;
        do{
            j=q.top();
            q.pop();
            instack[j]=0;
            type[j]=ans;   //標記j 屬於第幾個聯通分支
            vis[ans]++;    //這個聯通分支的點+1
           // printf("%d ans=%d\n",j,ans);
        }while(j!=x);
    }
}

void solve()
{
    int i,j;
    mem(time,0);
    mem(instack,0);
    mem(out,0);
    mem(vis,0);

    ans=tim_num=0;

    for(i=1;i<=n;i++)
        if(time[i]==0)
          tarjan(i);

	for(i=1;i<=n;i++)
		for(j=head[i];j!=-1;j=e[j].next)
	{
		int to=e[j].to;

		if(type[i]!=type[to])
			{
				out[type[i]]=1;  //標記有出度的聯通分支
			}
	}

	int t=0,pos;

	for(i=1;i<=ans;i++)    //一共有ans個聯通分支,取出其中
		if(out[i]==0)
	{
		t++;
		pos=i;
		if(t>1) break;
	}

   //如果出度為0的聯通分支只有一個,那麼這個聯通分支的個數就是答案,
   //否則,無解
	if(t==1)
		printf("%d\n",vis[pos]);
	else
		printf("0\n");


}

int main()
{
    int i,j;
    scanf("%d%d",&n,&m);
    {
        int u,v;
        e_num=0;

        mem(head,-1);

        while(m--)
        {
            sff(u,v);
            add(u,v);
        }
        solve();
    }
    return 0;
}






  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved