Codeforces 566E - Restoring Map(bitset 优化构造)
作者:互联网
本来说好的不做,结果今早又忍不住开了道题/qiao
我们称度为 \(1\) 的点为叶节点,度大于 \(1\) 的点为非叶节点。
首先考虑如何求出叶节点及其连边情况,这里不妨假设叶节点个数 \(\ge 3\),对于 \(\le 2\) 的情况特判掉,具体如何特判见下文。可以发现,对于两个非叶节点 \(x,y\),如果它们之间存在边相连,那么就一定存在两个点,到它们之间距离 \(\le 2\) 的点的集合恰好是 \(\{x,y\}\),具体构造就是取一个与 \(x\) 相连且 \(\ne y\) 的点,再取一个与 \(y\) 相连且 \(\ne x\) 的点。而如果存在两个点,满足它们交集恰好是 \(\{x,y\}\),那 \(x,y\) 之间必然存在边相连,否则如果 \(x,y\) 距离为 \(2\),那么这两点的交集中如果包含 \(x,y\),那么必然包含 \(x,y\) 的公共邻居,也就是 \(x,y\) 中间夹着的那个点,如果 \(x,y\) 距离为 \(3\),那么道理也是类似的,如果这两点的交集中如果包含 \(x,y\),那么必然包含 \(x,y\) 的之间的两个点,如果 \(x,y\) 距离 \(\ge 4\) 那么不可能存在两个点,到它们距离 \(\le 2\) 的点集中都包含 \(x,y\)。这个可以使用 bitset
及其自带 _Find_first
和 _Find_next
函数解决。
这样我们可以知道非叶节点之间的连边情况,接下来考虑如何将叶子挂上去。首先思考如何判断一个点是否对应一个叶节点的集合,显然对于一个非叶节点 \(x\) 及一个与其相连的叶节点 \(y\),必然有 \(y\) 对应的集合完全包含在 \(x\) 对应的集合中,这样我们遍历到一个点时,我们检验是否存在另一个集合完全包含在该集合中,如果有则跳过这个集合。这样可以保证我们遍历到的所有集合要么属于一个叶节点,要么属于一个不与任何点相连的非叶节点,对于后者而言显然不会对答案产生任何影响,因此我们不跳过它也罢。
接下来考虑如何判定一个叶节点的集合连向的是哪个非叶节点,我们去掉该集合中所有叶子节点(显然在第一步中我们已经知道哪些是叶子节点,而哪些不是),那么可以发现,去掉叶子节点后的集合,等于所有和与其相连的非叶节点的非叶节点组成的集合,而对于每个非叶节点,我们是知道哪些非叶节点与其相连的,这个同样可以 bitset
优化。
接下来找出这个非叶节点之后我们就可以知道所有与这个非叶节点相邻的叶节点了。具体方法就是找到这个集合中所有叶节点,显然这些叶节点都与这个非叶节点相邻。
这样我们就完美地处理了非叶节点个数 \(\ge 3\) 的情况,那如果非叶节点个数 \(\le 3\) 怎么办呢?
显然如果非叶节点个数 \(=1\),那么答案就是个菊花图,随便构造一个菊花图就行了。
如果非叶节点个数 \(=2\),那么所有叶子节点对应的集合大小都 \(<n\),而这种情况连向什么非叶节点是不重要的,因此我们仿照上面的过程,即对于一个叶子节点对应的集合,我们找出集合中所有叶子节点,那么这些叶子节点都应连向同一个非叶节点。
时间复杂度 \(\dfrac{n^3}{\omega}\)。
const int MAXN=1000;
int n;
bitset<MAXN+5> a[MAXN+5],b[MAXN+5],is;
int main(){
scanf("%d",&n);bool flg=1;
for(int i=1;i<=n;i++){
int len;scanf("%d",&len);flg&=(len==n);
while(len--){int x;scanf("%d",&x);a[i][x]=1;}
} if(flg){
for(int i=1;i<n;i++) printf("%d %d\n",i,n);
return 0;
} vector<pii> res;
for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
bitset<MAXN+5> tmp=a[i]&a[j];
if(tmp.count()==2){
int x=tmp._Find_first(),y=tmp._Find_next(x);
if(b[x][y]) continue;
b[x].set(y);b[y].set(x);is[x]=is[y]=1;
b[x][x]=b[y][y]=1;res.pb(mp(x,y));
}
} if(is.count()==2){
int r1=0,r2=0;
static int vis[MAXN+5];
for(int i=1;i<=n;i++) if(is[i]) (r1)?(r2=i):(r1=i);
for(int i=1;i<=n;i++) if(a[i].count()<n){
for(int j=1;j<=n;j++) if(!is[j]&&a[i][j]) vis[j]=1;
break;
}
for(int i=1;i<=n;i++) if(!is[i]){
if(vis[i]) res.pb(mp(r1,i));
else res.pb(mp(r2,i));
} for(pii e:res) printf("%d %d\n",e.fi,e.se);
} else {
static bool vis[MAXN+5];
for(int i=1;i<=n;i++){
bool flg=1;
for(int j=1;j<=n;j++) if((a[i]&a[j])==a[j]&&a[i]!=a[j])
flg=0;
if(!flg) continue;
bitset<MAXN+5> tmp=a[i]&is;
for(int j=1;j<=n;j++) if(tmp[j]&&b[j]==tmp){
if(!vis[j]){
for(int k=1;k<=n;k++) if(!is[k]&&a[i][k]) res.pb(mp(j,k));
vis[j]=1;
}
break;
}
} for(pii e:res) printf("%d %d\n",e.fi,e.se);
}
return 0;
}
/*
5
5 1 2 3 4 5
4 1 3 4 5
4 3 4 5 2
3 2 5 4
3 1 4 3
*/
标签:tmp,Map,566E,int,Codeforces,非叶,相连,集合,节点 来源: https://www.cnblogs.com/ET2006/p/Codeforces-566E.html