Codeforces.566E.Restoring Map(构造)

题目链接


\(Description\)

对于一棵树,定义某个点的邻居集合为所有距离它不超过\(2\)的点的集合(包括它自己)。
给定\(n\)及\(n\)个点的邻居集合,要求构造一棵\(n\)个点的树,使得每个给定的集合都对应一个点。输入保证有解。
\(n\leq1000\)。

\(Solution\)

如果两个点的邻居集合大小为\(2\),那么交集中的两个点之间一定有边。这样我们就可以\(O(\frac{n^3}{w})\)确定出非叶节点以及它们之间的连边。
然后考虑叶节点应该挂到哪里。如果一个叶节点的邻居集合,和距离某个非叶节点不超过\(1\)的点的集合相同,那么这两个点之间有边。对于叶子\(x\),所有包含\(x\)的邻居集合中最小的一定就是\(x\)的邻居集合。一个点数\(\geq3\)的树,离某个点距离不超过\(1\)的点的集合是互不相同的。
需要特判非叶节点只有一个和两个的情况。

官方题解是,找出叶子\(x\)的邻居集合,如果除去\(x\)集合大小\(\geq3\),那么在集合内度数\(>1\)的点就是与\(x\)相邻的。否则集合大小是\(2\),这种情况有些难判,但是与\(x\)相邻的点一定只与一个非叶节点相连。所以我们只需要特判\(x-a-b-...\)这种情况。
还有种并查集的写法,太傻逼了看不懂了QAQ。


//296ms 100KB
#include <cstdio>
#include <cctype>
#include <bitset>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=1003;

std::bitset<N> st[N],nle,adj[N];
bool not_leaf[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}

int main()
{
    int n=read();
    for(int i=1; i<=n; ++i)
        for(int T=read(); T--; st[i][read()]=1);
    int m=0;
    for(int i=1; i<=n; ++i)
        for(int j=i+1; j<=n; ++j)
            if((st[i]&st[j]).count()==2)
            {
                std::bitset<N> tmp=st[i]&st[j];
                int s=0,t=0;
                for(int k=1; k<=n&&!t; ++k) if(tmp[k]==1) s?t=k:s=k;//可以用_Find_next。但是暴力复杂度也是对的,暴力好咯。
                if(!adj[s][t])
                    ++m, printf("%d %d\n",s,t), nle[s]=nle[t]=1,
                    adj[s][s]=adj[s][t]=1, adj[t][t]=adj[t][s]=1, not_leaf[s]=not_leaf[t]=1;
            }
    if(!m)
    {
        for(int i=2; i<=n; ++i) printf("%d %d\n",1,i);
        return 0;
    }
    if(m==1)
    {
        int s=0,t=0,a=0,b=0;
        for(int i=1; i<=n&&!t; ++i) if(not_leaf[i]) s?t=i:s=i;
        for(int i=1; i<=n; ++i)
            if(st[i].count()!=n)
            {
                for(int j=1; j<=n; ++j) !not_leaf[j]&&printf("%d %d\n",j,st[i][j]?s:t);
                break;
            }
        return 0;
    }
    for(int i=1; i<=n; ++i)
        if(!not_leaf[i])
        {
            int mn=N,p=0;
            for(int j=1; j<=n; ++j) if(st[j][i]&&st[j].count()<mn) mn=st[j].count(), p=j;
            std::bitset<N> tmp=st[p]&nle;
            for(int j=1; j<=n; ++j)
                if(tmp[j]&&tmp==adj[j])
                    {printf("%d %d\n",i,j); break;}
        }

    return 0;
}

原文地址:https://www.cnblogs.com/SovietPower/p/10531749.html

时间: 2024-10-09 17:19:48

Codeforces.566E.Restoring Map(构造)的相关文章

Codeforces 534C Polycarpus&#39; Dice 构造

题意:给你n个筛子,第 i 个筛子有 可以表示范围 1-a[i]的数,给你最后筛子和,问你每个筛子不可能的值有多少个. 解题思路:得到每个筛子的取值范围. 解题代码: 1 // File Name: c.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月13日 星期一 00时38分58秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #includ

codeforces 250B Restoring IPv6

题目:大意是在说给定一个ipv6地址的简记形式,让你给它补全输出. 简记的规则大致是把地址中的一部分0去掉,其中还包括一连串的0,此时可用::来代替. 方法:首先记录给定的字符串中的:的个数,让后就能确定::中间要补全的0000的个数,然后对于每个小地址(例如bfd),补全失去的0就好了,这时候可以使用printf输出补0的功能,即:printf("%04s",s); 注意:本来每个字符串中:的个数是不能超过7个的,但是会出现::连用,就可能出现8个,这样对于计算::之间补全0000的

codeforces 509D Restoring Numbers

codeforces 509D Restoring Numbers 题意: v[i][j]=(a[i]+b[j])%k 现在给出n*m矩阵v[][], 求a[],b[]和k, 任意一种情况都行. 限制: 1 <= n,m <= 100; 0 <= v[i][j] <= 100 思路: 对于数组a[], 无论怎么变, 数组之间的差始终不变, b[]也同理 利用这个求出k 再设a[0]=0,b[0]=0,求出剩下的东西.

Codeforces 432E Square Tiling(构造+贪心)

我们通常这么写 using (SqlDataReader drm = sqlComm.ExecuteReader()) { drm.Read();//以下把数据库中读出的Image流在图片框中显示出来. MemoryStream ms = new MemoryStream((byte[])drm["Logo"]); Image img = Image.FromStream(ms); this.pictureBox1.Image = img; } 我的写数据 private void b

CodeForces 250B Restoring IPv6 解题报告

Description An IPv6-address is a 128-bit number. For convenience, this number is recorded in blocks of 16 bits in hexadecimal record, the blocks are separated by colons — 8 blocks in total, each block has four hexadecimal digits. Here is an example o

CodeForces 404C Restore Graph (构造)

题意:让人构造一个图,满足每个结点边的数目不超过 k,然后给出每个结点到某个结点的最短距离. 析:很容易看出来如果可能的话,树是一定满足条件的,只要从头开始构造这棵树就好,中途超了int...找了好久. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include <string> #include <cstdlib> #include

Codeforces 482B Interesting Array 构造+线段树判可行

题目链接:点击打开链接 题意: 构造一个n长的序列,m个限制: 每个限制[l, r] q 序列要满足 区间[l,r]的所有数 & 起来结果是q 思路: 直接构造,然后判可行就好了.. #include <stdio.h> #include <cstring> #include <iostream> #include <map> template <class T> inline bool rd(T &ret) { char c;

CodeForces - 401C Team(简单构造)

题意:要求构造一个字符串,要求不能有连续的两个0在一起,也不能有连续的三个1在一起. 分析: 1.假设有4个0,最多能构造的长度为11011011011011,即10个1,因此若m > (n + 1) * 2则肯定不能构造成功. 2.假设有4个0,则至少有3个1,若小于3个,则会有两个连续的0在一起,所以n > m + 1则肯定不能构造成功. 3.当n==m+1时,一定是01串. 4.当m>=n时,应以1为开头构造,根据m和n的个数决定放1个1还是2个连续的1. #include<

Codeforces 482A Diverse Permutation(构造)

题目链接:Codeforces 482A Diverse Permutation 题目大意:给定N和K,即有一个1~N的序列,现在要求找到一个排序,使得说所有的|pi?pi+1|的值有确定K种不同. 解题思路:构造,1,K+1,2,K,3,K-1,... K+2,K+3 ... N. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn