SCU - 4522 :寻找fly真迹(思维+染色法+完全图判断)

4522: 寻找fly真迹

Submit your solution   Discuss this problem   Best solutions

Time Limit: 2000 MS              Memory Limit: 256 M


一天fly正坐在课堂上发呆,突然,他注意到了桌面上的一个字符串S1S2S3S4...Sn,这个字符串只由字符"a","b"和"c"构成。刚好这堂课很无聊,所以他决定为这个字符串画一张图,(这张图上的每个点代表字符串中的一个字符,例如节点1代表S1。)这张图有以下特点:

1.它有n个点,从1到n进行标号。
2.对于图上任意的两个点i和j(i ≠ j),当两者代表的字符在字典序顺序上相邻或者相等的时候,会被连上一条边。也就是说,"a"-"b", "a"-"a"这类的,它们间会有一条边相连,而"a"-"c"这类的就没有边相连。

fly根据这个字符串画出了图,随后把原先的字符串擦除了,于是桌面只留下了图。xf听说了fly的光荣事迹,第二天决定去一睹真迹,于是他来到了fly那天所在的教室的那张桌子前,然而眼前的一幕让他惊呆了:桌子上出现了好多幅图,显然这是某个别有用心的同学(GooZy?)私自画上去的。这可急坏了xf,于是他想请你帮他找出哪幅才是fly真迹。

输入

输入包含多组数据。第一行为一个整数T(1 ≤ T ≤ 100),代表数据组数,对于每组数据: 第一行是两个整数n和m( 1 ≤ n ≤ 500, 0 ≤ m ≤ n(n − 1)/2 ),分别代表图上点的个数和边的个数。
然后是m行,每行两个整数uivi ( 1 ≤ ui, vi ≤ n, ui ≠ vi ),代表图上的一条边所连接的两个点。输入保证没有重边。

输出

如果是fly真迹,即这张图是由题目描述中的字符串构成的,则输出“Yes”,否则输出“No”(不包含双引号)。

样例输入

3

2 1
1 2

4 3
1 2
1 3
1 4

4 4
1 2
1 3
1 4
2 3

样例输出

Yes
No
Yes

HINT

对于样例1,fly见到的字符串可能长这个样子:aa, bb, cc...
对于样例2,结点1和其它所有的点相连,但是结点2、3、4互不相连,这说明这三者互不相邻,而我们只有三个字符,不可能存在这样的字符串满足这张图,所以这幅图不是fly的真迹。
对于样例3,我们可以构造这样的字符串“baac”来满足这张图。

解题思路:从题目中我们可以得到的信息:a于c一定不连通,b于任何字母都连通,所以我们只需要把b所连的边都去掉,那么剩下的a一定和所有的a都相连,c同理,即看看是否剩下a和c字母的两张强连通图即可,判断无向图是否强连通,只需要看每个点的度数是否等于总点数-1,统计a和c的点数我们利用二分图的染色法即可。
AC代码:
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<math.h>
#include<stdlib.h>
#include<queue>
#include<map>
#include<set>
#define bug printf("*********\n");
#define mem0(a) memset(a, 0, sizeof(a));
#define mem1(a) memset(a, -1, sizeof(a));
#define in1(a) scanf("%d" ,&a);
#define in2(a, b) scanf("%d%d", &a, &b);
#define out1(a) printf("%d\n", a);
#define out2(a, b) printf("%d %d\n", a, b);
#define pb(G, a, b) G[a].push_back(b);
using namespace std;
typedef long long LL;
typedef pair<int, int> par;
const int mod = 1e9+7;
const int INF = 1e9+7;
const int N = 1000010;
const double pi = 3.1415926;

int n, m, cnt, flag, idx; //idx用来染色
int head[510], du[510], color[510], sum[510], vis[510];
//sum数组用来统计a,c字母的个数

struct edge
{
    int to;
    int next;
}e[510*510];

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

void dfs(int k)
{
    for(int i = head[k]; i != -1; i = e[i].next) {
        int en = e[i].to;
        if(!vis[en]) {
            sum[idx] ++;
            color[en] = idx;
            vis[en] = 1;
            dfs(en);
        }
    }
}

int main()
{
    int T, x, y;
    scanf("%d", &T);
    while(T --) {
        mem0(vis);
        mem0(du);
        mem1(head);
        in2(n ,m);
        idx = 0;
        int s = 0; //记录有多少个b字母
        for(int i = 0; i < m; i ++) {
            in2(x, y);
            add(x, y);
            add(y, x);
            du[x] ++;
            du[y] ++;
            if(du[x] >= n-1) {
                vis[x] = 2; //vis[] = 2表示b
                s ++;
            }
            if(du[y] >= n-1) {
                vis[y] = 2;
                s ++;
            }
        }
        for(int i  = 1; i <= n; i ++) {
            du[i] -= s; //去掉b以后的度数
            if(!vis[i]) {
                sum[idx] = 1;
                vis[i] = 1;
                color[i] = idx;
                dfs(i);
                idx ++;
            }
        }
        if(idx > 2) printf("No\n"); //如果剩下三个及以上的图,则一定是错误的
        else {
            bool ok = true;
            for(int i = 1; i <= n; i ++) {
                if(vis[i] != 2 && du[i] != sum[color[i]] - 1) { //如果点的度数不等于总点数-1则不是强连通
                    ok = false;
                }
            }
            if(ok) printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值