1. 程式人生 > 其它 >Codeforces 1391 E. Pairs of Pairs —— dfs樹,想法,有丶東西

Codeforces 1391 E. Pairs of Pairs —— dfs樹,想法,有丶東西

技術標籤:想法dfs

This way

題意:

現在有一張連通圖,你要將這個圖選出至少(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; }