Codeforces 1391 E. Pairs of Pairs —— dfs樹,想法,有丶東西
阿新 • • 發佈:2020-12-11
題意:
現在有一張連通圖,你要將這個圖選出至少(n+1)/2個點,並且將其兩兩分組。使得每對二元組:(a,b),(c,d),這四個點在原圖中的連邊數不會超過2.
如果沒有的話,那就輸出至少(n+1)/2個點使得它們構成一條簡單路徑。
題解:
我是想著貪心取合法連通數最小的點來著…但是很難搞
首先最長路的話,我們可以像找到樹的直徑一樣去進行了兩遍dfs。
對於找到二元組的話,構造dfs樹,在同一深度的點,它們必定沒有連邊(如果有連邊的話,那麼肯定是先從一個走到另一個)並且,這樣構造出來的二元組,兩兩之間最多隻有兩條連邊,也就是一一對應
如果有第三條邊:
那麼上面兩個點的深度絕對不會相同。因此不需要考慮這種情況。
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
#define pii pair<int,int>
vector<int>son[N],dep[N];
vector<pii>ans;
int vis[N];
void dfs(int x,int d){
dep[d].push_back(x);
vis[x]=1;
for(int i:son[x]){
if(vis[ i])continue;
dfs(i,d+1);
}
}
int p,mx;
void dfs2(int x,int d){
if(d>mx)mx=d,p=x;
vis[x]=1;
for(int ne:son[x]){
if(vis[ne])continue;
dfs2(ne,d+1);
}
}
stack<int>s;
int lim,f;
void dfs3(int x){
if(f)return ;
s.push(x);
if(s.size()>=lim) {
printf("PATH\n%d\n",(int)s.size());
while(!s.empty()){
printf("%d ",s.top());
s.pop();
}
f=1;
return ;
}
vis[x]=1;
for(int ne:son[x]){
if(vis[ne])continue;
if(f)return ;
dfs3(ne);
if(s.size())
s.pop();
if(f)return ;
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n,m,x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)son[i].clear(),dep[i].clear(),vis[i]=0;
while(!s.empty())s.pop();
ans.clear();
f=mx=p=0;
for(int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
son[x].push_back(y),son[y].push_back(x);
}
dfs(1,1);
for(int i=2;!dep[i].empty();i++){
int sz=dep[i].size();
for(int j=0;j<sz-1;j+=2)
ans.push_back({dep[i][j],dep[i][j+1]});
}
lim=(n+1)/2;
if(lim%2)lim++;
if(ans.size()>=lim/2){
printf("PAIRING\n%d\n",ans.size());
for(pii i:ans)
printf("%d %d\n",i.first,i.second);
continue;
}
for(int i=1;i<=n;i++)
vis[i]=0;
dfs2(1,1);
for(int i=1;i<=n;i++)
vis[i]=0;
dfs3(p);
}
return 0;
}