专栏文章
P13537 题解
P13537题解参与者 5已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @mioknaag
- 此快照首次捕获于
- 2025/12/02 20:45 3 个月前
- 此快照最后确认于
- 2025/12/02 20:45 3 个月前
不难发现一个图有解当且仅当它联通。
一个朴素的想法是,把最终的结果按照列分割成若干块,每块宽 格,两边全部放同一种颜色 ,中间放与 相邻的颜色。
当然为了确保相邻块的 之间有连边,需要找一棵生成树并在必要的时候回溯。为了方便实现,使用 dfs 生成树。
这个做法可以做到 。
现在我们保留生成树,递归地构造答案。如果生成树上一个点 有多个儿子,那么是说,这个点是子树中所有点导出子图的一个割点,删掉之后导出子图变成多个联通块。
用 将它的不同子树分隔开来,有如下构造:
CPPxxxxxxxxx
x1x2x3x4x
xxxxxxxxx
x...x...x
x...x...x
x...x...x
x...x...x
其中两个
. 的连通块代表 的不同子树,数字代表子树中与 有边相连的点。显然这个构造可以做到宽度 ,长度 ,尝试进一步优化。
为了保证构造中
CPP1234 的位置不和其他东西相邻,需要把与它直接相邻的位置填上 x,因而可以挖掉角上的位置得到_x_x_x_x_
x1x2x3x4x
xx.xxx.xx
x...x...x
x...x...x
x...x...x
x...x...x
或者
CPPx_x_x_x_x
xx1x2x3xx
x.x.x.x.x
x...x...x
x...x...x
x...x...x
x...x...x
其中
_ 为上一层用掉的部分。相邻层之间交错排列,这样就可以做到 。发现最外面一层的数字上面不需要放东西,可以再省掉一层,做到 。
显然如果一个子树大小为 ,那么按照这种构造,上面一层至少会留下 个位置可以用来填数。子树内至多有 个与 相邻的点,其中又有至少一个是它的儿子,因此 个是够用的。
CPP#include<bits/stdc++.h>
using namespace std;
#define ll int
const ll N=250;
int n,m,k,ans[N][N],ok[N],vis[N],TO[N][N];
vector<int> to[N];
void dfs(int u){
vis[u]=1;
for (auto v:to[u]) if (ok[v]&&vis[v]==0) dfs(v);
}
void del(vector<int>& vec,int x){
if (vec.size()==0) return;
for (int i=0;i<vec.size();++i) if (vec[i]==x){
swap(vec[i],vec.back());break;
}
if (vec.back()==x) vec.pop_back();
}
void solve(vector<int> vec,int l,int r,int h){
assert(vec.size());assert(r-l==(vec.size()-1)*2);
int u=vec[0];
if (vec.size()==1){
for (int i=1;i<=h;++i) for (int j=l;j<=r;++j) ans[i][j]=u;
for (int i=l;i<=r;++i) if (ans[h+1][i]==0) ans[h+1][i]=u;
return;
}
for (auto x:vec) ok[x]=1;
dfs(u);
for (auto x:vec) assert(vis[x]);
for (auto x:vec) vis[x]=0;
for (int i=1;i<=h;++i) ans[i][l]=ans[i][r]=u;
for (int i=l;i<=r;++i) ans[h][i]=u;
if (ans[h+1][l]==0) ans[h+1][l]=u;
if (ans[h+1][r]==0) ans[h+1][r]=u;
int d=l+1+(ans[h+1][l+1]!=0);
for (auto x:to[u]) if (ok[x]){
assert(d<r);
assert(ans[h+1][d]==0);
ans[h+1][d]=ans[h-1][d]=u;
ans[h][d]=x;
d+=2;
}
while(d<r){
assert(ans[h+1][d]==0);
ans[h+1][d]=ans[h][d]=ans[h-1][d]=u;
d+=2;
}
d=l;
for (int i=1;i<=n;++i) ok[i]=0;
del(vec,u);
while(vec.size()){
int v=0;
for (auto x:vec) if (TO[u][x]){v=x;break;}
assert(v);
vector<int> nxt(1,v);
for (auto x:vec) ok[x]=1;
dfs(v);
for (auto x:vec) if (vis[x]&&x!=v) nxt.emplace_back(x);
for (auto x:nxt) del(vec,x);
solve(nxt,d+1,d+2*nxt.size()-1,h-2);
d+=2*nxt.size();
for (int i=1;i<=h;++i) ans[i][d]=u;
for (int i=1;i<=n;++i) ok[i]=vis[i]=0;
}
assert(d==r);
}
vector<vector<int> > create_map(int N,int M,vector<int> A,vector<int> B){
memset(ans,0,sizeof(ans));
n=N;m=M;
for (int i=0;i<m;++i){
to[A[i]].emplace_back(B[i]);
to[B[i]].emplace_back(A[i]);
TO[A[i]][B[i]]=TO[B[i]][A[i]]=1;
}
m=0;k=2*n;
vector<int> vec;
for (int i=1;i<=n;++i) vec.emplace_back(i);
solve(vec,1,k-1,k);
vec.clear();
for (int i=1;i<=n;++i) to[i].clear();
for (int i=1;i<=n;++i) for (int j=1;j<=n;++j) TO[i][j]=0;
for (int i=1;i<=k;++i) ans[i][k]=ans[i][k-1];
vector<vector<int> > ans(k,vector<int>(k,0));
for (int i=1;i<=k;++i) for (int j=1;j<=k;++j) ans[i-1][j-1]=::ans[i][j];
return ans;
}
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...