[codeforces 1228D] Complete Tripartite C++ 题解

题面描述

[题意翻译]
有一个n个顶点m条边的无向图,在一对顶点中最多有一条边。
设v1,v2是两个不相交的非空子集,当满足以下条件时f(v1,v2)为真
1、v1中的点之间不存在边
2、v2中的点之间不存在边
3、对于在v1,v2中的每一对顶点,x在v1中,y在v2中,x,y之间有边
所有点集不为空,且不相交,是否有v1,v2,v3使得f(v1,v2)、f(v2,v3)、f(v3,v1)均为真
如果有输出每个点所在的点集(1,2,3),否则输出-1

输入格式

第一行输入n,m。 n ≤ 1 e 5 , m ≤ 3 e 5 n \le 1e5 , m\le3e5 n1e5,m3e5
接下来m行,每行两个数a,b。表示a,b间有一条无向边。

输出格式

如果有输出每个点所在的点集(1,2,3),否则输出-1

思路

这道题分步做,
首先考虑没有直接相连的点一定是一个集合。那么我们取三个没用过的点,把和这三个点直接相连的点分到对应的组。
然后我们check三个组是否满足条件即可。
注意我们的分组方式,同一组中,两个点之间可能有边相连。这种情况也是-1。

/*
* @Author: chenkexing
* @Date:   2019-10-29 17:38:47
* @Last Modified by:   chenkexing
* @Last Modified time: 2019-10-29 18:20:01
*/
// #pragma GCC optimize(2)
// #pragma GCC optimize(3)
// #pragma GCC optimize(4)
#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>
//#include <unordered_set>
//#include <unordered_map>
// #include<bits/extc++.h>
// using namespace __gnu_pbds;
using namespace std;
#define pb push_back
#define fi first
#define se second
#define debug(x) cerr<<#x << " := " << x << endl;
#define bug cerr<<"-----------------------"<<endl;
#define FOR(a, b, c) for(int a = b; a <= c; ++ a)

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9+7;


template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x=f?-x:x;
}

/**********showtime************/
            const int maxn = 1e5+9;
            set<int>mp[maxn];
            vector<int>zu[4];
            int vis[maxn];
            pii edge[maxn*3];
            int cnt[maxn];
            int n, m;
            /*** 把不直接相连的点放到一组***/
            int pushZu(int u, int id) {
                vis[u] = id;
                zu[id].pb(u);
                queue<int>que;

                for(int i=1; i<=n; i++) {
                    if(vis[i]) continue;
                    if(mp[u].find(i) == mp[u].end()) {
                        vis[i] = id;
                        zu[id].pb(i);
                    }
                    else que.push(i);
                }
                if(que.empty()){ return 0;}
                return que.front();
            }


            /*** 检查每个s组中的点与t组中的点两两有边相连 ***/
            bool check(int s, int t) {
                for(int i=1; i<=n; i++) cnt[i] = 0;
                for(int i=1; i<=m; i++) {
                    int u = edge[i].fi, v = edge[i].se;
                    if(vis[u] == s && vis[v] == t) {
                        cnt[u]++;
                    }
                    if(vis[u] == t && vis[v] == s) {
                        cnt[v]++;
                    }
                }
                for(int i=0; i<zu[s].size(); i++) {
                    if(cnt[zu[s][i]] != zu[t].size()) return false;
                }
                return true;
            }


int main(){
            scanf("%d%d", &n, &m);
            for(int i=1; i<=m; i++) {
                int u, v;
                scanf("%d%d", &u, &v);
                mp[u].insert(v);
                mp[v].insert(u);
                edge[i] = pii(u, v);
            }
            int flag = 1;

            int nx = pushZu(1, 1);
            if(nx <= 0) {flag = 0;}
            else {
                nx = pushZu(nx, 2);
                if(nx <= 0) {flag = 0;}
                else {
                    nx = pushZu(nx, 3);
                    if(nx != 0) {flag = 0;}
                }
            }

            /***由于选点的方式, 每组中的两点之间可能存在边***/
            ll tot = zu[1].size() * zu[2].size() +  zu[2].size() * zu[3].size() + zu[1].size() * zu[3].size();
            if(tot != m) flag = 0;


            if(flag == 0) puts("-1");
            else {
                if(check(1, 2) && check(2, 3) && check(3, 1)) {
                    for(int i=1; i<=n; i++) printf("%d ", vis[i]);
                    puts("");
                }
                else puts("-1");
            }

            return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值