UOJ496 新年的新航线

Link
如果\(n\ne3\)那么一定有解。
我们考虑这样一种构造方式:每次找到\((a,b,c)\)三个点,选\((a,b),(a,c)\)这两条边,然后把\(b,c\)两个点删掉。
很显然这样构造出来的生成树一定是合法的。
那么我们递归地构造,每次按上面所说选两条边并删两个点,并且为了方便需要保证删完点之后依旧是一个多边形。
对于一个点\(x\),我们求出它后面的\(4\)个点\(a,b,c,d\)
因为我们保证任意时刻删完点后它是一个多边形,因此\((x,a),(a,b),(b,c),(c,d)\)都一定存在。
因为我们需要保证删完点后它还是一个多边形,因此\(x,d\)这两个点是不能删的。
那么我们就只需要考虑删掉\((a,b,c)\)中的两个的三种情况了。
如果\((x,b),(b,d)\)存在我们就把\((a,b),(b,c)\)选上,然后把\(a,c\)删掉。
如果\((x,c),(x,b)\)存在我们就把\((x,a),(x,b)\)选上,然后把\(a,b\)删掉。
如果\((x,c),(a,c)\)存在我们就把\((a,c),(b,c)\)选上,然后把\(a,b\)删掉。
可以发现这么操作一定是满足我们上面所说的所有要求的。
如果成功删了的话我们递归处理,把\(x\)移到\(x\)的前一个点。
如果没能删的话我们把\(x\)移到\(x\)的下一个点。
当剩余点数不超过\(5\)时我们一定可以找到一个点,它跟其它的点都有连边,那么我们以这个点为根其它的点作为叶子节点即可构造一个合法的生成树。
维护前后的点用链表就可以了。

#include<cstdio>
#include<cctype>
#include<unordered_map>
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(int x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    void write(int x,int c){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put(c);}
}
using IO::read;
using IO::write;
const int N=500007;
int k,c,a[100],L[N],R[N];
std::unordered_map<int,int>e[N];
void del(int x){R[L[x]]=R[x],L[R[x]]=L[x];}
void out(int u,int v){write(u,' '),write(v,'\n');}
void dfs(int x)
{
    if(k<=5)
    {
	a[c=1]=x;
	for(int i=R[x];i^x;i=R[i]) a[++c]=i;
	for(int i=1,j;i<=k;++i)
	{
	    for(j=1;j<=k;++j) if(i^j&&!e[a[i]][a[j]]) break;
	    if(j>k){for(j=1;j<=k;++j) if(i^j) out(a[i],a[j]);return ;}
	}
    }
    for(int i=x;;i=R[i])
    {
	int a=R[i],b=R[a],c=R[b],d=R[c];
	if(e[i][c])
	{
	    if(e[i][b]) return del(a),del(b),k-=2,dfs(L[i]),out(i,a),out(i,b);
	    if(e[a][c]) return del(a),del(b),k-=2,dfs(L[i]),out(a,c),out(b,c);
	}
	if(e[i][b]&&e[b][d]) return del(a),del(c),k-=2,dfs(L[i]),out(a,b),out(c,b);
    }
}
int main()
{
    int n=read();
    if(n==3) return !printf("-1");
    for(int i=1,u,v;i<=n-3;++i) u=read(),v=read(),e[u][v]=e[v][u]=1;
    for(int i=1;i<=n;++i) L[i]=i-1,R[i]=i%n+1,e[i][i%n+1]=e[i%n+1][i]=1;
    L[1]=n,k=n,dfs(1),IO::Flush();
}
posted @ 2020-02-10 22:26  Shiina_Mashiro  阅读(271)  评论(0编辑  收藏  举报