@xiaoziyao
2021-08-15T11:39:27.000000Z
字数 2840
阅读 887
解题报告
CF1477D Nezzar and Hidden Permutations解题报告:
给定一个无向图,将它定向为一个 DAG,求出两个拓扑序让两个拓扑序相同的结点数最少。
。
埋藏在任务计划的陈年老题。/tuu
首先观察样例,发现很多点都可以拓扑序不相同,我们考虑先求出固定点,然后让其他的结点巧妙地安排顺序使得两个拓扑序不同。
我们发现我们可以每次找到一个与所有点都有连边的点,然后把它删掉,重复这个过程,就可以获得所有固定点,我们钦定它们全部放在最开始的拓扑序。
然后会剩下 个度数不超过 的点,这个性质难以利用,考虑补集转换,那么它的补图每个点度数一定大于 。
那么我们考虑对每个连通块求出一个 dfs 树,对每棵树进行菊花剖分,然后对于每个菊花都可以安排两种顺序:先中心再四周,先四周再中心,不难发现这样每个点的两个拓扑序一定不相同。
如何进行菊花剖分呢?(我们只需要大小大于 的菊花)我们可以对于每个点 分类讨论:如果它附近有没有划分的点那么直接把 和这些点划分成一个菊花。否则如果 与某一个中心相邻,则将 划分入这个菊花。(注意这里必须判断,原因是菊花剖分的过程中中心可能移动,具体见下方)如果还是不行,考虑与 相邻的这个菊花,如果大小大于 , 可以直接拿走一个点;否则可以移动这个菊花的中心到另一个点上,并将 放入。
我们发现这样一定会让每个点不重不漏地划分入若干个菊花,时间复杂度 。
坑点:
#include<stdio.h>
#include<set>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxn=500005;
int T,n,m,tot,cols;
int ans1[maxn],ans2[maxn],deg[maxn],col[maxn],cen[maxn],size[maxn];
vector<int>v[maxn],t[maxn];
set<int>s;
queue<int>q;
map<pair<int,int>,int>mp;
void dfs1(int x,int last){
for(set<int>::iterator it=s.begin();it!=s.end();it++)
if(mp.find(make_pair(*it,x))==mp.end())
t[x].push_back(*it),t[*it].push_back(x);
for(int i=0;i<t[x].size();i++)
if(t[x][i]!=last)
s.erase(t[x][i]);
for(int i=0;i<t[x].size();i++)
if(t[x][i]!=last)
dfs1(t[x][i],x);
}
void dfs2(int x,int last){
if(col[x]==0){
int flg=0;
for(int i=0;i<t[x].size();i++)
if(col[t[x][i]]==0)
flg=1;
if(flg){
col[x]=++cols,cen[cols]=x,size[cols]=1;
for(int i=0;i<t[x].size();i++)
if(col[t[x][i]]==0)
col[t[x][i]]=cols,size[cols]++;
}
else{
if(cen[col[t[x][0]]]==t[x][0])
col[x]=col[t[x][0]],size[col[t[x][0]]]++;
else if(size[col[t[x][0]]]==2)
col[x]=col[t[x][0]],cen[col[t[x][0]]]=t[x][0],size[col[t[x][0]]]++;
else col[x]=++cols,cen[cols]=x,size[cols]=2,size[col[t[x][0]]]--,col[t[x][0]]=cols;
}
}
for(int i=0;i<t[x].size();i++)
if(t[x][i]!=last)
dfs2(t[x][i],x);
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
s.insert(i);
for(int i=1;i<=m;i++){
int x,y;;
scanf("%d%d",&x,&y);
v[x].push_back(y),v[y].push_back(x),deg[x]++,deg[y]++;
mp[make_pair(x,y)]=mp[make_pair(y,x)]=1;
}
for(int i=1;i<=n;i++)
if(deg[i]==n-1)
s.erase(i),q.push(i);
while(!q.empty()){
int x=q.front();
printf("x=%d\n",x);
q.pop(),ans1[x]=ans2[x]=++tot;
for(int i=0;i<v[x].size();i++){//travel all nodes
int y=v[x][i];
deg[y]--;
if(s.find(y)!=s.end()&°[y]>=n-tot-1)
s.erase(y),q.push(y);
}
}
for(int i=1;i<=n;i++)
if(s.find(i)!=s.end())
s.erase(i),dfs1(i,0);
for(int i=1;i<=n;i++)
if(col[i]==0&&ans1[i]==0)
dfs2(i,0);
for(int i=1;i<=cols;i++){
ans1[cen[i]]=++tot;
for(int j=0;j<t[cen[i]].size();j++){
int k=t[cen[i]][j];
if(col[k]==i)
ans2[k]=tot,ans1[k]=++tot;
}
ans2[cen[i]]=tot;
}
for(int i=1;i<=n;i++)
printf("%d%c",ans1[i],i==n? '\n':' ');
for(int i=1;i<=n;i++)
printf("%d%c",ans2[i],i==n? '\n':' ');
tot=cols=0,mp.clear();
for(int i=1;i<=n;i++)
deg[i]=col[i]=ans1[i]=0,v[i].clear(),t[i].clear();
}
return 0;
}