• 「PMOI-4」可怜的团主


    一、题目

    点此看题

    这道题考试时候打了缩点,然后一无所获,虽然想出了那个超级神奇的构造方法。

    还是不要思维定式啊,我以为难的图论题一定要缩点,但是我从来一打缩点就爆炸

    二、解法

    比较传统的树上二选一构造问题,根据套路任何情况一定有解

    直接考虑 ( t dfs) 树,叶子之间一定无边,如果有 (geqlfloorfrac{n}{3} floor) 个叶子(不考虑根),那么我们找到解。

    那么有叶子数量 (<lfloorfrac{n}{3} floor),考虑根是叶子也只有至多 (lfloorfrac{n}{3} floor) 个点,那么我们把它们两两匹配得到路径至多有 (lceilfrac{n}{6} ceil) 条。

    现在问题转化成了构造一个叶子的匹配,使得树上所有点都被覆盖。我的方法:把所有叶子按 ( t dfs) 序排序,设一共有 (k) 个叶子(如果 (k) 是奇数那么我们补上根),然后 (i)(i+frac{k}{2}) 匹配。

    已经过了,跪求上面叶子匹配构造方法的正确性证明。
    UPD:有一个巨佬在我的博客下面评论了证明,我觉得他的证明是对的。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int M = 1005;
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,k,tot,Ind,cnt,f[M],dfn[M];
    int fa[M],id[M],dep[M],a[M],b[M];
    struct edge
    {
    	int v,next;
    }e[M*M];
    void dfs(int u)
    {
    	dfn[u]=++Ind;int sz=0;
    	dep[u]=dep[fa[u]]+1;
    	for(int i=f[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(dfn[v]) continue;
    		fa[v]=u;dfs(v);
    		sz++;
    	}
    	if(sz==0 || (sz==1 && u==1))
    		id[++k]=u;
    }
    int cmp(int x,int y)
    {
    	return dfn[x]<dfn[y];
    }
    void match(int u,int v)
    {
    	int t1=0,t2=0;cnt++;
    	while(u!=v)
    	{
    		if(dep[u]>dep[v])
    			a[++t1]=u,u=fa[u];
    		else
    			b[++t2]=v,v=fa[v];
    	}
    	a[++t1]=u;
    	printf("%d ",t1+t2);
    	for(int i=1;i<=t1;i++)
    		printf("%d ",a[i]);
    	for(int i=t2;i>=1;i--)
    		printf("%d ",b[i]);
    	puts("");
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=m;i++)
    	{
    		int u=read(),v=read();
    		e[++tot]=edge{v,f[u]},f[u]=tot;
    		e[++tot]=edge{u,f[v]},f[v]=tot;
    	}
    	dfs(1);int fl=0;
    	if(id[k]==1) k--,fl=1;
    	if(k>=n/3)
    	{
    		puts("2");
    		for(int i=1;i<=n/3;i++)
    			printf("%d ",id[i]);
    		puts("");
    		return 0;
    	}
    	if(fl==1) id[++k]=1;
    	if(k%2) id[++k]=1;
    	sort(id+1,id+1+k,cmp);
    	puts("1");
    	for(int i=1;i<=k/2;i++)
    		match(id[i],id[i+k/2]);
    	for(int i=2;i<=n;i++)
    		if(cnt<(n+5)/6)
    		{
    			printf("%d %d
    ",1,i);
    			cnt++;
    		}
    }
    
  • 相关阅读:
    redis 数据迁移
    redis
    Redis集群的三种模式
    Golang 协程 (goroutine) 与通道 (channel)
    Python生成器next方法和send方法区别
    python 文件
    Tornado 异步以及非阻塞的I/O
    python 多进程和多线程3 —— asyncio
    利用CSS改变图片颜色的100种方法!
    jquery获取div的位置
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15168202.html
Copyright © 2020-2023  润新知