URAL 1742 Team building

题目大意:

某个公司有n个程序员,每个程序员心中都认为自己是公司最好的程序员或者认为自己是第二好的

现在要将程序员们分成多个team,每次先选出一个当前没有被分组的程序员创立一个组,然后这个程序员认为最好的那个程序员如果没有加入任何组织的话,就将那个程序员加入这个组,同时在考虑新加入这个组的程序员认为最好的那个人,直到当前这个组里的程序员认为最好的人已经被分组。这个组就分配完毕,重新选择新的未分组的人创立新的组进行分配,直到所有人分配完毕。

现在给出所有的编号为i的程序员认为最好的程序员的编号 nex[i],问最多能分出多少组,最少能分出多少组


大致思路:

首先,这是一个有着n条有向边,n个顶点的图,要使得分的组数少的话,就是先每次选入度为零的点进行标记,然后沿着有向边一路标记下去,这样子可以有k1个组 ( k1 为入度是0的点的数量) 然后处理成环且环上的点都没有与其它入度为零的点有连接的情况,得到k2,那么 k1 + k2 即为答案

至于要最大分组,便是  总人数n - 形成环的人的个数 x  + 环的个数y

代码如下:

Result  :  Accepted     Memory  :  1692 KB     Time  :  46 ms

/*
 * Author: Gatevin
 * Created Time:  2014/7/23 12:30:27
 * File Name: test.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

int n;
int nex[100010];
int vis[100010];
int step[100010];
int notzero[100010];
int main()
{
   while( scanf("%d",&n) == 1)
   {
    memset(notzero, 0, sizeof(notzero));
    for(int i = 1; i <= n; i++)
    {
        scanf("%d",&nex[i]);
        notzero[nex[i]] = 1;
    }
    memset(vis, 0, sizeof(vis));
    memset(step, 0, sizeof(step));
    int now = 1;
    int cnt = 0;
    int loop = 0;
    int tmp;
    for(int i = 1; i <= n; i++)
    {
        tmp = i;
        if(vis[i] == 0)
        {
            vis[i] = now;
            step[i] = 1;
            while(!vis[nex[i]])
            {
                vis[nex[i]] = now;
                step[nex[i]] = step[i] + 1;
                i = nex[i];
            }
            if(vis[i] == vis[nex[i]])
            {
                cnt += (step[i] - step[nex[i]] + 1);
                loop++;
            }
        }
        now++;
        i = tmp;
    }
    memset(vis, 0, sizeof(vis));
    int answer = 0;
    for(int i = 1; i <= n; i++)
    {
        tmp = i;
        if(!notzero[i])
        {
            vis[i] = 1;
            answer++;
            while(!vis[nex[i]])
            {
                i = nex[i];
                vis[i] = 1;
            }
        }
        i = tmp;
    }
    for(int i = 1; i <= n; i++)
    {
        tmp = i;
        if(!vis[i])
        {
            answer++;
            vis[i] = 1;
            while(!vis[nex[i]])
            {
                i = nex[i];
                vis[i] = 1;
            }
        }
        i = tmp;
    }
    printf("%d %d\n",answer, n - cnt + loop);
   }
    return 0;
}

/*
2
1 2 
2 2 

2 
2 1 
1 1 

6
1 3 4 2 6 5 
3 3
*/

/*
12
 2 3 4 5 2 4 8 11 8 7 12 9
3 6 

16
2
3
4
1
3
5
5
2
4
9
12
13
11
14
16
16
*/



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值