蓝桥杯选拔F

设有一个由 n 个人组成的社团。社团中的每个成员给社团中的一个成员发送一条短信。如果有一个由社团成员组成的子社团,每个子社团中成员恰好收到一条由该子社团成员发送的短信,则称这个子社团为一个和谐子社团。和谐短信问题要求社团的最大和谐子社团。例如,设有一个由 7 个人组成的社团。将社团中的成员编号为:0,1,…,6。他们分别发送一条短信给社团成员:1,0,0,2,2,3,6。则容易看出社团成员 0,1,6 构成一个最大和谐子社团。

★算法设计: 对于给定的由 n 个人组成的社团以及社团员间发送短信的信息,设计一个计算最大和谐子社团的算法。

Input
对于每组输入数据,输入数据的第 1 行有 1 个正整数 n (1<=n<=600,000),表示社团由 n 个人组成。将社团中的成员编号为:0,1,…,n-1。第 i 个人发送一条短信给社团中成员 f (i) ,0 <= i < n ,0 <= f (i) < n 。文件的第 2 行是 f (i) 的值, 0 <= i < n 。
Output
输出计算出的社团的最大和谐子社团大小。
Sample Input
7
1 0 0 2 2 3 6
Sample Output

3

很容易发现是要选出最多的点使得每个点的入度都是1;然后就想到了以下算法:

1.把入度为0的点去掉(入度只有可能减少,不可能增加),同时把与这个点的相连的线去掉;

2.重复1,直到没有入度为0的点;

3.剩下的点集就是最大和谐子社团(入度为0的点都去掉了,所有所有点的入度比然大于等于1,又因为出度为1,所以剩下的点入度都为1)。


但是写的时候发现写不出(可能是STL的优先队列没学好,要是哪位大佬会用优先队列实现代码借在下观摩一下),然后就换了一种方法,反过来写:

1.记录入度变为0的点;

2.将入度为0的点相连的线去掉;

3重复1、2,直到没有变成入度为0的点;


#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include<queue>
#include<vector>

using namespace std;
typedef long long LL;
const double PI = acos(-1.0);
const double eps = 1e-6 ;
const int INF = 1e9 ;
const int maxn = 600000+10 ;
const int mod = 1000000;

int to[maxn],getCount[maxn];
int que[maxn];
void inti(int n)
{
    int i;
    for( i=0;i<=n;i++)
        getCount[i]=0;
}
int main()
{
    int n;

    int i,first,last,t,ans;
    while(~scanf("%d",&n))
    {
        inti(n);
        for( i=0;i<n;i++)
        {
            scanf("%d",&to[i]);
            getCount[to[i]]++;
        }

         first=0,last=0;
        for( i=0;i<n;i++)
        {
            if(getCount[i]==0)
                que[last++]=i;

        }

        while(first!=last)
        {
             t=que[first];
            first++;
            getCount[to[t]]--;
            if(getCount[to[t]]==0)
                que[last++]=to[t];
        }
         ans=0;
        for( i=0;i<n;i++)
        {
            if(getCount[i])
                ans++;
        }

        printf("%d\n",ans);

    }
    return 0;
}


posted on 2017-12-12 21:46  一零七  阅读(88)  评论(0编辑  收藏  举报

导航