题解:P11978 [KTSC 2021] 铁路 / railroad
ainivolAGEM · · 题解
前情提要:更好的阅读体验。
题意
题目给出一颗
分析
首先,如果重新编号所有点变成图的话我们就无法确认原来的根、叶子之类的节点,所以我们考虑先把所有
我们发现,如果我们把总节点放在一个叶子节点,那么该点相连的边有
但其实还有个问题,如果还有一个与标记节点直接相连的点原本也连接了
-
如果是与总节点同父亲的节点,那么可证明我们必定有比当前总节点深度更大的叶子节点,我们选择深度最大的叶子节点作为总节点就可以让所有同父亲叶子节点都只连
1 条边,也就不可能达到K +1 。 -
如果是标记节点的父亲节点,由于
K \leq 1 ,我们可以直接将其中一条新边连接总节点和标记节点的父亲节点,那么我们就可以辨认哪个是总节点了。
还有一个小的误区:对于
AC code
#include<bits/stdc++.h>
#include<utility>
using namespace std;
typedef int ll;
typedef pair<ll,ll> pir;
const int N=304;
ll rt,id,tid,mdep,d[N];
ll tot,head[N];
struct Edge{
ll to,nxt;
}e[N<<1];
void add_edge(ll u,ll v){
e[++tot].to=v;
e[tot].nxt=head[u];
head[u]=tot;
}
void init(){
for(int i=1;i<=tot;i++){
e[i].to=e[i].nxt=0;
}
rt=id=tid=mdep=tot=0;
memset(head,0,sizeof(head));
memset(d,0,sizeof(d));
}
void dfs(ll u,ll fa,ll dep){
bool flag=true;
for(int i=head[u];i;i=e[i].nxt){
ll v=e[i].to;
if(v==fa){
d[u]++;
continue;
}
dfs(v,u,dep+1);
flag=false;
d[u]++;
}
if(flag&&dep>mdep){
id=u;
rt=fa;
mdep=dep;
}
}
vector<pir> encode_map(ll N,ll K,ll &X,vector<pir> E){
init();
for(int i=0;i<E.size();i++){
add_edge(E[i].first,E[i].second);
add_edge(E[i].second,E[i].first);
}
dfs(1,0,1);
vector<pir> ans;
X=rt;
for(int i=head[rt];i;i=e[i].nxt){
ll v=e[i].to;
if(d[v]!=1){
if(d[v]-1==K){
ans.push_back(make_pair(v,id));
}
tid=v;
}
}
for(int i=1;ans.size()<K;i++){
if(i!=rt&&i!=id&&i!=tid){
ans.push_back(make_pair(id,i));
}
}
return ans;
}
vector<pir> decode_map(ll N,ll K,ll X,vector<pir> E){
init();
for(int i=0;i<E.size();i++){
add_edge(E[i].first,E[i].second);
add_edge(E[i].second,E[i].first);
}
for(int i=head[X];i;i=e[i].nxt){
ll v=e[i].to;
for(int j=head[v];j;j=e[j].nxt){
d[v]++;
}
if(d[v]-1==K){
id=v;
}
}
vector<pir> ans;
for(int i=0;i<E.size();i++){
if(E[i].first==id||E[i].second==id){
if(E[i].first!=X&&E[i].second!=X){
continue;
}
}
ans.push_back(make_pair(E[i].first,E[i].second));
}
return ans;
}
一些易错点:
-
在统计与之相连的边数时别忘记考虑根节点。
-
通信题,别写错了,真的。
-
记得初始化。