codeforces 1228D Complete Tripartite(图论+思维)

传送门

题意:给定一张不保证联通的简单图,问是否存在染色方案,使得每一个连通块为三分图。

分析:不考虑其他约束,只考虑三分图每一个子集内部没有边相连的约束,先染出一张图。做法为首先对于一个连通块,先选定一个起点u,将u染成1,然后将与u直接相连的点,全部染成2,然后选择一个染成2的点为v,然后将所有与v直接相连的点w染色,其中如果w未染色,那么将w染成1,如果w被染成2,将w染成3。然后再判断这个染色的图是否符合条件。

对于所有的联通块,维护连通块内三种色块中点的数量,如果有一个联通块的某一种色块数量为0,说明连通块内凑不满三个子集,不合法。

对于一个点,如果他直接连接的点数为当前联通块其他两种颜色点的数量之和,则合法,否则不合法。

对于一条边,如果联通颜色相同的点,不合法。

代码中的判断可能有冗余。

代码:

#include 
#define mp make_pair
#define debug(x) cout << #x << ": " << x << endl
#define pb push_back
typedef long long LL;
const int maxn = 3e5 + 10;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
using namespace std;
int n, m, u, v, col[maxn], f[maxn], sz[maxn];
int find(int x) {
    return f[x] == -1 ? x : f[x] = find(f[x]);
}
vector<int> g[maxn];
vector<int> s[maxn][3];
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 0; i < m; ++i) {
        cin >> u >> v;
        g[u].pb(v);
        g[v].pb(u);
    }
    for (int i = 1; i <= n; ++i)
        f[i] = -1;
    for (int i = 1; i <= n; ++i) {
        if (col[i] == 0) {
            col[i] = 1;
            int fu = find(i);
            if (g[i].empty()) {
                cout << -1;
                exit(0);
            }
            int to = g[i][0];
            for (int j = 0; j < g[i].size(); ++j) {
                int _to = g[i][j];
                int fv = find(_to);
                if (fv != fu)
                    f[fv] = fu;
                col[_to] = 2;
            }
            for (int j = 0; j < g[to].size(); ++j) {
                int _to = g[to][j];
                if (_to == i)
                    continue;
                int fv = find(_to);
                if (fv != fu)
                    f[fv] = fu;
                if (col[_to] == 0)
                    col[_to] = 1;
                else if (col[_to] == 2)
                    col[_to] = 3;
                else {
                    cout << -1;
                    exit(0);
                }
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        v = find(i);
        s[v][col[i] - 1].pb(i);
    }
    for (int i = 1; i <= n; ++i)
        if (!s[i][0].empty() || !s[i][1].empty() || !s[i][2].empty()) {
            if (s[i][0].empty() || s[i][1].empty() || s[i][2].empty()) {
                cout << -1;
                exit(0);
            }
        }
    for (int i = 1; i <= n; ++i) {
        v = find(i);
        if (col[i] == 1) {
            if (s[v][1].size() + s[v][2].size() != g[i].size()) {
                cout << -1;
                exit(0);
            }
        }
        else if (col[i] == 2) {
            if (s[v][0].size() + s[v][2].size() != g[i].size()) {
                cout << -1;
                exit(0);
            }
        }
        else if (col[i] == 3) {
            if (s[v][0].size() + s[v][1].size() != g[i].size()) {
                cout << -1;
                exit(0);
            }
        }
        for (int j = 0; j < g[i].size(); ++j) {
            int to = g[i][j];
            if (col[to] == col[i]) {
                cout << -1;
                exit(0);
            }
        }
    }
    for (int i = 1; i <= n; ++i)
        cout << col[i] << " ";
}
View Code

 

你可能感兴趣的:(codeforces 1228D Complete Tripartite(图论+思维))