Codeforces Round #394 (Div. 2) E. Dasha and Puzzle 构造 坐标离散化

本文探讨了一种特殊的树状结构网格布局算法,该算法能够确保树形结构在二维网格中放置时仅包含横向和纵向边,并且这些边不会相互交叉。通过巧妙地设置每个层级的边长比例,即使子树形状各异,也能避免它们之间的碰撞。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给一颗树,问是否能够放到网格图里,保证只有横边和竖边,且边与边不相交。


解法:

开脑洞,先想能不能找到这样的树,树应该至少满足一个要求:

1.根节点能有4个儿子,非根节点最多只有3个儿子。

满足要求1,理论上就一定能找到这样的树,即可以另深度为d的边比深度为d+1的边长很多很多,这样使得各个方向的子图离的尽量远,不管子树的图形再怎么乱,子树和子树之间也不会碰在一起。

满足这个要求的极限条件就是下面这个不等式:

2^0+2^1+...+2^(k-1)=2^k-1<2^k,可以刚好不碰到,故深度1-k的边长依次为2^k,2^(k-1),...,2^1,2^0。

构造完树之后,坐标离散化一下可以让节点坐标缩在0~n-1之间。

代码依次为去重离散化,未去重离散化,未离散化版本,题目给的范围不需要离散化也能过:


#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned int uii;
const ll dx[4]={0,-1,0,1};
const ll dy[4]={-1,0,1,0};
int n,u,v,n1,n2;
ll rx[31],ry[31];
vector<ll> x,y;
vector<int> vec[31];
void dfs(int u,int fa,ll x,ll y,ll d,int dir) {
    int id=0;
    rx[u]=x;
    ry[u]=y;
    for (uii i=0;i<vec[u].size();++i) {
        int v=vec[u][i];
        if (v==fa)
            continue;
        if (dir!=-1&&((id&1)==(dir&1)&&id!=dir))
            ++id;
        if (id>=4) {
            puts("NO");
            exit(0);
        }
        dfs(v,u,x+dx[id]*d,y+dy[id]*d,d>>1,id);
        ++id;
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n-1;++i) {
        scanf("%d%d",&u,&v);
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    dfs(1,-1,0,0,1LL<<n,-1);
    for (int i=1;i<=n;++i) {
        x.push_back(rx[i]);
        y.push_back(ry[i]);
    }
    sort(x.begin(),x.end());
    x.erase(unique(x.begin(),x.end()),x.end());
    sort(y.begin(),y.end());
    y.erase(unique(y.begin(),y.end()),y.end());
    puts("YES");
    for (int i=1;i<=n;++i)
        printf("%ld %ld\n",lower_bound(x.begin(),x.end(),rx[i])-x.begin(),lower_bound(y.begin(),y.end(),ry[i])-y.begin());
    return 0;
}


#include <cstdio>
#include <vector>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned int uii;
const ll dx[4]={0,-1,0,1};
const ll dy[4]={-1,0,1,0};
int n,u,v,id1[31],id2[31];
ll rx[31],ry[31];
vector<int> vec[31];
bool cmp1(int a,int b) {
    return rx[a]<rx[b];
}
bool cmp2(int a,int b) {
    return ry[a]<ry[b];
}
void dfs(int u,int fa,ll x,ll y,ll d,int dir) {
    int id=0;
    rx[u]=x;
    ry[u]=y;
    for (uii i=0;i<vec[u].size();++i) {
        int v=vec[u][i];
        if (v==fa)
            continue;
        if (dir!=-1&&((id&1)==(dir&1)&&id!=dir))
            ++id;
        if (id>=4) {
            puts("NO");
            exit(0);
        }
        dfs(v,u,x+dx[id]*d,y+dy[id]*d,d>>1,id);
        ++id;
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
        id1[i]=id2[i]=i;
    for (int i=0;i<n-1;++i) {
        scanf("%d%d",&u,&v);
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    dfs(1,-1,0,0,1LL<<n,-1);
    sort(id1+1,id1+n+1,cmp1);
    sort(id2+1,id2+n+1,cmp2);
    puts("YES");
    for (int i=1;i<=n;++i)
        printf("%ld %ld\n",lower_bound(id1+1,id1+n+1,i,cmp1)-id1,lower_bound(id2+1,id2+n+1,i,cmp2)-id2);
    return 0;
}

#include <cstdio>
#include <vector>
#include <cstdlib>
using namespace std;
typedef long long ll;
typedef unsigned int uii;
const ll dx[4]={0,-1,0,1};
const ll dy[4]={-1,0,1,0};
int n,u,v;
ll rx[31],ry[31];
vector<int> vec[31];
void dfs(int u,int fa,ll x,ll y,ll d,int dir) {
    int id=0;
    rx[u]=x;
    ry[u]=y;
    for (uii i=0;i<vec[u].size();++i) {
        int v=vec[u][i];
        if (v==fa)
            continue;
        if (dir!=-1&&((id&1)==(dir&1)&&id!=dir))
            ++id;
        if (id>=4) {
            puts("NO");
            exit(0);
        }
        dfs(v,u,x+dx[id]*d,y+dy[id]*d,d>>1,id);
        ++id;
    }
}
int main()
{
    scanf("%d",&n);
    for (int i=0;i<n-1;++i) {
        scanf("%d%d",&u,&v);
        vec[u].push_back(v);
        vec[v].push_back(u);
    }
    dfs(1,-1,0,0,1LL<<n,-1);
    puts("YES");
    for (int i=1;i<=n;++i)
        printf("%lld %lld\n",rx[i],ry[i]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值