【洛谷】1477:[NOI2008]假面舞会【图论】

P1477 [NOI2008]假面舞会

题目描述

一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。

今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一 个自己喜欢的面具。每个面具都有一个编号,主办方会把此编号告诉拿该面具的人。

为了使舞会更有神秘感,主办方把面具分为k (k≥3)类,并使用特殊的技术将每个面具的编号标在了面具上,只有戴第i 类面具的人才能看到戴第i+1 类面具的人的编号,戴第k 类面具的人能看到戴第1 类面具的人的编号。

参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己算出有多少类面具,于是他开始在人群中收集信息。

栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第2号面具的人看到了第5 号面具的编号。栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去。

由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信 息不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具。由于主办方已经声明了k≥3,所以你必须将这条信息也考虑进去。

输入输出格式

输入格式:

 

第一行包含两个整数n, m,用一个空格分隔,n 表示主办方总共准备了多少个面具,m 表示栋栋收集了多少条信息。接下来m 行,每行为两个用空格分开的整数a, b,表示戴第a 号面具的人看到了第b 号面具的编号。相同的数对a, b 在输入文件中可能出现多次。

 

输出格式:

 

包含两个数,第一个数为最大可能的面具类数,第二个数为最小可能的面具类数。如果无法将所有的面具分为至少3 类,使得这些信息都满足,则认为栋栋收集的信息有错误,输出两个-1。

输入输出样例

输入样例#1: 复制
6 5
1 2
2 3
3 4
4 1
3 5
输出样例#1: 复制
4 4
输入样例#2: 复制
3 3
1 2
2 1
2 3
输出样例#2: 复制
-1 -1

说明

50%的数据,满足n ≤ 300, m ≤ 1000;

100%的数据,满足n ≤ 100000, m ≤ 1000000。


Solution

有思维难度而没有算法难度的奇奇怪怪的图论题==

分情况讨论八。

如果只有环的情况,明显就是所有环的长度取gcd是种类的最大值。如果又有环又有链,链实际上没用,只用判环就好。如果只有链,那么把所有链拼到一起,总长度就是种类数的最大值,最小值就是3-ans能被ans整除的最小值。

关于环,如果建出来的正图没有环,但是变成无向图是有环,如何去判断?就建反边,正边权为1,反边权为-1,正常跑dfs判环就可以叻。

【注意】环长度每次是取绝对值!!!(有可能是负的减正的)

还有一个有趣的事实:任何数和0取gcd结果都是它本身!!

Code

#include<bits/stdc++.h>
using namespace std;

int n, m;

struct Node {
    int v, nex, w;
    Node(int v = 0, int nex = 0, int w = 0) :
        v(v), nex(nex), w(w) { }
} Edge[2000005];

int h[100005], stot;
void add(int u, int v, int d) {
    Edge[++stot] = Node(v, h[u], d);
    h[u] = stot;
}

int gcd(int a, int b) {
    return b == 0 ? a : gcd(b, a % b);
}

int vis[100005], dep[1000005], ans, len, lenmi, lenma;
void dfs(int u, int deep) {
    if(!vis[u]) {
        vis[u] = 1;
        dep[u] = deep;
        lenmi = min(lenmi, deep);
        lenma = max(lenma, deep);
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            dfs(v, deep + Edge[i].w);
        }
    } else ans = gcd(ans, abs(deep - dep[u]));
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i ++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v, 1); add(v, u, -1);
    }
    for(int i = 1; i <= n; i ++)
        if(!vis[i])    {
            dfs(i, 0);
            len += lenma - lenmi + 1;
            lenmi = lenma = 0;
        }
    if(ans >= 3) {
        for(int i = 3; i <= ans; i ++)
            if(ans % i == 0) {
                printf("%d %d", ans, i);
                break;
            }
    } else if(ans == 0 && len >= 3)    printf("%d 3", len);
    else printf("-1 -1");
    return 0;
}
原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9776235.html