Codeforces 566E - Restoring Map(bitset 優化構造)
本來說好的不做,結果今早又忍不住開了道題/qiao
我們稱度為 \(1\) 的點為葉節點,度大於 \(1\) 的點為非葉節點。
首先考慮如何求出葉節點及其連邊情況,這裡不妨假設葉節點個數 \(\ge 3\),對於 \(\le 2\) 的情況特判掉,具體如何特判見下文。可以發現,對於兩個非葉節點 \(x,y\),如果它們之間存在邊相連,那麼就一定存在兩個點,到它們之間距離 \(\le 2\) 的點的集合恰好是 \(\{x,y\}\),具體構造就是取一個與 \(x\) 相連且 \(\ne y\) 的點,再取一個與 \(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
*/