2262: master(vector + dfs)

这就是!!!

题目描述

有N个人,编号为1至N,他们相互之间拜师学艺。

某个时刻,如果甲向乙拜师,一般情况下乙就将甲收为徒弟。这时乙会将甲视为大徒弟,而所有甲的徒弟(如果有的话)便成为乙的小徒弟。

但是,每个人都不想收太多的大徒弟。如果乙当前大徒弟数量超过他的期望值,他便会拒绝甲,而让甲拜自己的某一位大徒弟为师。甲总是想选好的师傅,而如果一个人的所有徒弟数量很多,往往说明他水平比较高,所以甲会选乙的徒弟中,拥有最多徒弟的人。如果有不止一个人徒弟最多,甲会选择最早向乙拜师的那位。于是接下来,就是新的一次拜师过程,甲向乙的某位徒弟拜师。甲直到拜师成功才会停止。

每个人每一时刻最多只会有一个师傅。有师傅的人若再向其他人拜师,就会先断绝与当前师傅的师徒关系。若甲不认乙为师,乙也就不认甲为大徒弟,同时甲和他的徒弟们也因此与甲的师傅脱离关系(当然包括师傅的师傅,师傅的师傅的师傅……)。

两个人之间的师徒关系可能是变化的。所以若甲向乙多次拜师,则甲向乙拜师的时间将以最后一次拜师的时间算。

一开始,每个人都没有师傅,也没有徒弟。我们事先告诉你每个人愿意收的最多大徒弟数量,达到了这个数量,他就不再收大徒弟,除非又有某个大徒弟与他断绝了关系。接下来每一时刻,就有人相互拜师,而所有拜师都会按照上面的规则进行。此外,一个人也不会向自己当前的任何一位徒弟拜师。
请你统计,所有拜师过程结束后,每个人有多少大徒弟,小徒弟。

输入

第一行给出两个整数N和M(5<=N<=10000,0<=M<=10000),其中N表示总人数,M表示有多少组拜师的人。

第二行,包含N个正整数,依次表示每个人愿意收的最多大徒弟的数量。

接下来M行,每行两个整数A和B,按时间顺序依次表示一对拜师的人。总是A向B拜师。

输出

输出包括N行,每行有两个整数,之间用一个空格隔开。第i行的两个数分别表示,在所有拜师结束后,编号为i的人拥有的大徒弟数量和小徒弟数量。

样例输入

6 7
2 2 2 2 2 2
2 1
3 1
4 1
5 1
6 1
6 3
3 2

样例输出

1 4
2 2
1 0
1 1
0 0
0 0

思路

仔细读题实现不难就是麻烦。
拜师的时候分两种情况:

  • 第一次拜师
    1. 师傅的徒弟人数没有满直接加入。
    2. 师傅的徒弟人数已满,递归找到人数最多的徒弟(找人数最多的徒弟的徒弟…)直到找到徒弟的徒弟还没有满就加入
  • 第 2~N 次拜师
    1. 把原来的师徒关系解散,(自己的徒弟不用管)
    2. 重复第一次拜师的过程

主要用到vector 哪里不会点哪里~

AC代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<stack>
#include<vector>
#define N 10004  
using namespace std;
vector<int>ve[N];
int d[N], tea[N];
int num, flag;
int dfs(int x) {    //找X的所有徒弟,记得使用前 NUM初始化为零 
    int t = ve[x].size();
    if(t) {
        num += t;
    }else {
        return 0;
    }
    for(int i = 0; i < t; i++) {
        dfs(ve[x][i]);
    }
    return num;
}
void find(int x) {  //找到一个合适的徒弟,让别人拜 
    if(ve[x].size() < d[x]) {
        flag = x;
        return ;
    }
    int uu, MAX = -1;
    for(int i = 0; i < ve[x].size(); i++) {
        num = 0;    //使用dfs前初始为零 
        int t = dfs(ve[x][i]);
        if(t > MAX) {
            MAX = t;
            uu = ve[x][i];
        }
    }
    find(uu);
    if(flag)
        return  ;
}
int main() {
//  freopen("in.txt", "r", stdin);
    int n, m;
    while(scanf("%d %d", &n, &m) != EOF) {
        for(int i = 1; i <= n; i++)
            ve[i].clear();
        memset(tea, 0, sizeof(tea));
        for(int i = 1; i <= n; i++) {
            scanf("%d", &d[i]);
        }
        for(int i = 0; i < m; i++) {
            int u, v;
            scanf("%d %d", &u, &v);
//          if(tea[u] == v)     //题上说:可以重复拜师,但是取最后一次 
//              continue;       //个人感觉加上这句话不对 (因为后面的拜师,可能影响原来的关系)
                                //以重复拜师,结果可能不一样.但是这样也对。 
                                //各位大佬请解释。。。
            if(tea[u]) {          
                vector<int>::iterator it;
                it = find(ve[tea[u]].begin(), ve[tea[u]].end(), u); 
                ve[tea[u]].erase(it);   //解除原来的师徒关系
            }
            if(ve[v].size() < d[v]) {   //师傅的徒弟人数还没有满 
                tea[u] = v;
                ve[v].push_back(u);
            }else {
                flag = 0;
                find(v);
                tea[u] = flag;
                ve[flag].push_back(u);
            }           
        }
        for(int i = 1; i <= n; i++) {
            num = 0;    //记得初始为零 
            int t = dfs(i);
            printf("%d %d\n", ve[i].size(), t - ve[i].size());
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/henuyh/article/details/80140075
dfs