• 【CF566E】Restoring Map(构造)


    点此看题面

    • 有一棵(n)个点的树,乱序给出与每个点距离小于等于(2)的点集。
    • 求构造一棵合法的树。
    • (nle10^3)

    非叶节点间的连边

    两个非叶节点(x,y)之间存在边,则对于它们两侧的两点(i,j),同时与(i,j)距离小于等于(2)的点只有(x,y)两点。

    因此,非叶节点(x,y)之间有边的充要条件就是存在两个点集的交集恰好是({x,y})。要求这个,只需用枚举一对点集用(bitset)优化即可。

    叶节点的连边

    对于叶节点,显然它对应的点集是所有包含它的点集中最小的那个(可能有多个最小的,是和它同父节点的兄弟们,肯定都一样)。

    而要找它的父节点,则它点集中所有的非叶节点应该恰好是它父节点的连边集合(加上父节点本身)。因此只要找到一个点的连边集合和修改后的点集相同,这个点就是它的父节点。

    非叶节点很少时的判断

    首先,如果没有非叶节点,则(n=2),直接判断即可。

    其次,如果非叶节点数量为(1),那么这是一张菊花图,所有点的点集都是(1sim n),很容易判断出来,然后只要随便找个点做菊花图的中心即可。

    再次,如果非叶节点数量为(2),先按照之前的方法求出这两个叶节点,那么点集可以被划分成两部分,随便分给这两个点即可。

    代码:(O(frac{n^3}{32}))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 1000
    using namespace std;
    int n,p[N+5],w[N+5][N+5];bitset<N+5> s,S[N+5],E[N+5];
    namespace FastIO
    {
    	#define FS 100000
    	#define tc() (FA==FB&&(FB=(FA=FI)+fread(FI,1,FS,stdin),FA==FB)?EOF:*FA++)
    	#define pc(c) (FC==FE&&(clear(),0),*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);}
    	Tp I void writeln(Con Ty& x,Con Ty& y) {write(x),pc(' '),write(y),pc('
    ');}
    }using namespace FastIO;
    int main()
    {
    	#define Exit return clear(),0
    	RI i,j,x,y;for(read(n),i=1;i<=n;++i) for(read(x);x;--x) read(y),S[i].set(y);if(n==2) {writeln(1,n);Exit;}//特判无叶节点
    	for(i=1;i<=n;++i) {for(j=1;j<=n&&S[i].test(j);++j);if(j<=n) break;}if(i>n) {for(i=2;i<=n;++i) writeln(1,i);Exit;}//特判一个叶节点
    	RI t=0;for(i=1;i<=n;++i) for(j=i+1;j<=n;++j) (s=S[i]&S[j]).count()==2&&(x=s._Find_first(),//枚举每对点集求交
    		y=s._Find_next(x),!w[x][y]&&(writeln(x,y),E[x].set(y),E[y].set(x),p[x]=p[y]=w[x][y]=w[y][x]=1,++t));//一对非叶节点间的连边
    	if(t==1) {for(i=1;i<=n&&S[i].count()==n;++i);for(j=1;j<=n;++j) !p[j]&&(writeln(S[i].test(j)?x:y,j),0);Exit;}//特判两个叶节点
    	for(i=1;i<=n;++i) p[i]&&(E[i].set(i),0);for(i=1;i<=n;++i) if(!p[i])//枚举每个非叶节点找父节点
    	{
    		for(t=0,j=1;j<=n;++j) S[j].test(i)&&(!t||S[j].count()<S[t].count())&&(t=j);//找所在最小点集
    		for(s.reset(),j=1;j<=n;++j) S[t].test(j)&&p[j]&&(s.set(j),0);for(j=1;j<=n;++j) if(E[j]==s) {writeln(i,j);break;}//删去叶节点找父节点
    	}return clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    Android Canvas save() restore()
    Android Custom View
    Android Canvas drawArc()
    每日一记--2014.9.15
    每日一记--2014.9.14
    每日一记--2014.9.13
    每日一记--2014.9.12
    每天一记--2014.9.11
    每日一记,今天开始
    java中的Iterator和Iterable
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF566E.html
Copyright © 2020-2023  润新知