图论 ---- E. Bear and Forgotten Tree 2(判补图的联通性技巧 图遍历的优化 条件拆分)

题目大意


题目大意:

给你 n n n个点, m m m对关系表示 ( a i , b i ) (a_i,b_i) (ai​,bi​)之间是没有边的问你能否构建出一颗树满足 1 1 1号点的度数为 k k k?


解题思路:

如果没有后面的条件就是判断这个图的补图的连通性
但是怎么判呢?
这里就是我们直接对点进行bfs每个点只访问一次。因为直接用边转移的话那么复杂度是 O ( n + m ) m ∈ [ 0 , n 2 ] , n ∈ [ 1 , 1 e 5 ] O(n+m)m\in[0,n^2],n\in[1,1e5] O(n+m)m∈[0,n2],n∈[1,1e5]不可以结束我们可以直接去枚举点,每个点只会访问一次对于不能存在的边用 s e t set set去判断
那么复杂度就可以降成了 O ( n + m ′ l o g ( m ′ ) ) , m ′ 是 不 能 存 在 的 边 ∈ [ 1 , 1 e 5 ] O(n+m'log(m')),m'是不能存在的边\in[1,1e5] O(n+m′log(m′)),m′是不能存在的边∈[1,1e5]

我们是不是直接判连通性就对后面那个条件好处理了呢?很明显

对于最后一个条件,我们直接统计有多少个连通块 c n t cnt cnt?和每个连通块之间有多少个点是可以和1相连的 n u m num num?

那么肯定是 c n t ≤ k    & &    n u m ≥ k cnt \leq k \;\&\&\; num \ge k cnt≤k&&num≥k 才行的!!还有就是每个连通块都要和1去连接


AC code

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
   read(first);
   read(args...);
}
int n, m, k;
int blocknum, flag = 1, block1;
set<PII> edge;
set<int> node;
bool vis[maxn];

inline int bfs(int u) {
    int num = 0;
    queue<int> q;
    q.push(u);
    node.erase(u);
    while(!q.empty()) {
        auto top = q.front();
        q.pop();
        vis[top] = 1;
        if (!edge.count({1, top}) && !edge.count({top, 1})) num ++;
        for(set<int>::iterator it = node.begin(); it != node.end();) {
            if(!edge.count({top,*it})&&!edge.count({*it,top})) {
                q.push(*it);
                node.erase(it++);
            } else it ++;
        }
    }
    return num;
}

int main() {
    IOS;
    cin >> n >> m >> k;
    for(int i = 1; i <= m; ++ i) {
        int u, v;
        cin >> u >> v;
        edge.insert({u,v});
        edge.insert({v,u});
    } 
    for(int i = 2; i <= n; ++i)  node.insert(i);
    for(int i = 2; i <= n; ++ i) 
       if(!vis[i]) {
           int tmp = bfs(i); // 如果有一个快和1无法联通肯定不行
           if(!tmp) {
               flag = 0;
               break;
           } else block1 += tmp;
           blocknum ++;
       }
    if(flag && block1 >= k && blocknum <= k) puts("possible");
    else puts("impossible");
    return 0;
}
上一篇:Eclipse使用


下一篇:超图 wpf地图控件加载地图