• [CF566E] Restoring Map


    [题目链接]

    https://codeforces.com/contest/566/problem/E

    [题解]

    定义叶子节点为度数为 (1) 的节点 , 非叶节点为度数非 (1) 的节点。

    首先考虑非叶节点数 (> 3) 的情况 , 两个非叶节点之间右边当且仅当能找到两个集合使得其交集为 ({x , y})

    于是可以通过 (bitset) 优化枚举 , 将这部分的复杂度做到 (O(frac{N ^ 3}{w}))。(具体实现时 , 注意 (Findfirst()) 函数和 (FindNext()) 函数的使用)。

    现在我们通过这种方式找到了所有非叶节点。

    考虑如何找到叶子节点的父亲。

    显然 , 对于每个叶子节点 , 在所有包含它的集合中 , 节点数最少的必然是它所代表的集合。

    不妨称连边集合为一个非叶节点与和它相连的非叶节点构成的集合。 因为一个叶子节点去掉与其相连的叶子节点等于其父亲的连边集合 , 而连边集合互不相同 , 故可以唯一确定。这里同样可以用 (bitset) 优化。

    最后来考虑非叶节点数量少于三个的情况。

    如果不存在 , (N = 2)

    如果只有一个 , 那么是一个菊花图的形式。

    如果有两个非叶节点 ,这两个非叶节点的连边集合是一样的。此时叶子的集合只有两种,选其中一种里的叶子挂在一个非叶节点下,另一种里的叶子挂在另外一个非叶节点下即可。

    时间复杂度 : (O(frac{N ^ 2}{w}))

    [代码]

    #include<bits/stdc++.h>
     
    using namespace std;
     
    typedef long long LL;
     
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
     
    const int MN = 1e3 + 5;
     
    int N , v[MN] , w[MN] , cnt , x , y;
    bitset< MN> a[MN], b[MN], e[MN];
     
    int main() {
    	 
    	 scanf("%d" , &N);
    	 if (N == 2) {
    	 	printf("1 2
    ");
    	 	return 0;
    	 }
    	 bool ok = 1;
    	 for (int i = 1 , j , k; i <= N; ++i) {
    	 	 scanf("%d" , &k);
    	 	 if (k != N) ok = 0;
    	 	 while (k--) scanf("%d" , &j) , a[i][j] = 1;
    	 }
    	 if (ok) {
    	 	for (int i = 1; i < N; ++i)
    	 		printf("%d %d
    " , N , i);
    	 	return 0;
    	 }
    	 for (int i = 1; i <= N; ++i)
    	 	for (int j = i + 1; j <= N; ++j) {
    	 		bitset < MN > o = a[i] & a[j];
    			if (o.count() != 2) continue;
    			int x = o._Find_first() , y = o._Find_next(x);
    			if (e[x][y]) continue;
    			printf("%d %d
    " , x , y); 
    			e[x][y] = e[y][x] = v[x] = v[y] = 1;	
    		}
    	 for (int i = 1; i <= N; ++i) 
    	 	 if (!v[i]) {
    	 	 	 int s = N + 1 , o = 0;
    			 for (int j = 1; j <= N; ++j) {
    			 	 if (!w[j] && a[j][i]) {
    			 	 	 int c = a[j].count();
    					 if (c < s) s = c , o = j;	
    				 }
    			 }	
    			 b[i] = a[o] , w[o] = 1;
    		 } else e[i][i] = 1 , ++cnt;
    	 if (cnt == 2) {
    	 	 for (int i = 1; i <= N; ++i)
    	 	 	if (v[i]) x = i;
    	 	 for (int i = N; i >= 1; --i)
    	 	 	if (v[i]) y = i;
    	 	 for (int i = 1; i <= N; ++i) 
    	 	 	if ((int) a[i].count() != N) {
    	 	 		for (int j = 1; j <= N; ++j) {
    	 	 			if (v[j]) continue;
    					if (a[i][j]) printf("%d %d
    " , x , j);
    					else printf("%d %d
    " , y , j);	
    				}	
    				break;
    			}
    		 return 0;
    	 }
    	 for (int i = 1; i <= N; ++i)
    	 	if (!v[i]) {
    	 		for (int j = 1; j <= N; ++j)
    	 			if (!v[j]) b[i][j] = 0;
    			for (int j = 1; j <= N; ++j)
    				if (v[j] && b[i] == e[j]) {
    					printf("%d %d
    " , i , j);
    					break;
    				}		
    		}
         return 0;
    }
    
  • 相关阅读:
    窗口
    DataTemplateSelector
    CompositeCollection
    Drawing
    模板
    集合视图
    绑定
    动画
    【数据结构初学】(java实现篇)——队列(转)
    慕课学习手记!(完成查找书籍小程序~)
  • 原文地址:https://www.cnblogs.com/evenbao/p/14438784.html
Copyright © 2020-2023  润新知