【LOJ】#2493. 「BJOI2018」染色

题面

题解

推结论大题……然而我推不出什么结论

奇环显然是NO

如果一个联通块里有两个分离的环,也是NO

如果一个联通块里,点数为n,边数为m
m <= n的时候,是YES

m >= n + 2的时候,肯定是NO

m = n + 1的时候
如果只存在一个双联通分量的话,取出这个双联通分量,存在两个点点度为3

他们之间有3条路径,如果其中两条为2的话答案是YES,否则是NO

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 20005
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    if(c == '-') f = -1;
    c = getchar();
    }
    while(c >= '0' && c <= '9') {
    res = res * 10 + c - '0';
    c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
struct node {
    int to,next;
}E[MAXN * 2];
int N,M,head[MAXN],sumE,col[MAXN];
int dfn[MAXN],low[MAXN],idx,sta[MAXN],top,cnt,Ecnt,Ncnt,tot;
int vis[MAXN],tims,deg[MAXN],path[5],pc;
vector<int> ver[MAXN];
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void Init() {
    read(N);read(M);
    sumE = 0;memset(head,0,sizeof(head));
    memset(col,0,sizeof(col));memset(vis,0,sizeof(vis));tims = 0;
    memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));idx = 0;
    int u,v;
    for(int i = 1 ; i <= M ; ++i) {
    read(u);read(v);
    add(u,v);add(v,u);
    }
}
bool color(int u) {
    if(!col[u]) col[u] = 2;
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(!col[v]) {
        col[v] = col[u] ^ 1;
        if(!color(v)) return false;
    }
    else if(col[v] == col[u]) return false;
    }
    return true;
}
void Tarjan(int u) {
    dfn[u] = low[u] = ++idx;
    sta[++top] = u;
    ++Ncnt;
    for(int i = head[u] ; i ; i = E[i].next) {
    ++Ecnt;
    int v = E[i].to;
    if(dfn[v]) {low[u] = min(low[u],dfn[v]);}
    else {
        Tarjan(v);
        if(low[v] >= dfn[u]) {
        int t = 1;
        ++tot;ver[tot].clear();ver[tot].pb(u);
        while(1) {
            int x = sta[top--];
            ++t;
            ver[tot].pb(x);
            if(x == v) break;
        }
        if(t >= 4) ++cnt;
        }
        low[u] = min(low[u],low[v]);
    }
    }
}
void dfs_path(int u,int fa,int ed,int dep) {
    if(u == ed) {path[++pc] = dep;return;}
    for(int i = head[u] ; i ; i = E[i].next) {
    int v = E[i].to;
    if(vis[v] == tims && v != fa) {
        dfs_path(v,u,ed,dep + 1);
    }
    }
}
void Solve() {
    for(int i = 1 ; i <= N ; ++i) {
    if(!col[i]) {
        if(!color(i)) {puts("NO");return;}
    }
    } 
    
    for(int i = 1 ; i <= N ; ++i) {
    if(!dfn[i]) {
        top = 0;cnt = 0;Ecnt = 0;Ncnt = 0;tot = 0;
        Tarjan(i);
        Ecnt /= 2;
        if(Ecnt <= Ncnt) continue;
        if(Ecnt >= Ncnt + 2) {puts("NO");return;}
        if(cnt >= 2) {puts("NO");return;}
        ++tims;
        int st,ed;
        for(int j = 1 ; j <= tot;  ++j) {
        if(ver[j].size() >= 4) {
            for(int k = 0 ; k < ver[j].size() ; ++k) {
            vis[ver[j][k]] = tims;
            deg[ver[j][k]] = 0;
            }
            for(int k = 0 ; k < ver[j].size() ; ++k) {
            int u = ver[j][k];
            for(int h = head[u] ; h ; h = E[h].next) {
                int v = E[h].to;
                if(vis[v] == tims) {
                ++deg[u];
                }
            }
            }
            st = 0;ed = 0;
            for(int k = 0 ; k < ver[j].size() ; ++k) {
            int u = ver[j][k];
            if(deg[u] == 3) {
                if(!st) st = u;
                else if(!ed) ed = u; 
            }
            }
            break;
        }
        }
        pc = 0;
        dfs_path(st,0,ed,0);
        sort(path + 1,path + pc + 1);
        if(path[1] == 2 && path[2] == 2) continue;
        else {puts("NO");return;}
    }
    }
    puts("YES");
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    int T;
    read(T);
    while(T--) {
    Init();
    Solve();
    }
    return 0;
}

转载于:https://www.cnblogs.com/ivorysi/p/9984078.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值