1. 程式人生 > >Codeforces 454E&453C Little Pony and Summer Sun Celebration 高妙思路構造題

Codeforces 454E&453C Little Pony and Summer Sun Celebration 高妙思路構造題

文章目錄

題意

n m

,
4 × n , 使
, 0 , 1 . 1. 給定一張n個點m條邊的無向圖,構造一條長度\leq 4\times n的路徑,使得每一個點被經過的次數的奇偶性符合輸入的情況,0為偶數,1為奇數.\newline不能輸出-1.

題解

先判 1 -1 .
稍微思考,發現如果含有要求通過奇數次的點的連通塊的個數超過 1 1 ,因為一條路徑不能穿過連通塊,顯然無解.這個特判一下就行.
剩下的情況肯定有解.我們構造這張圖的任意一棵生成樹,以任意一個要求通過奇數次的點為根對這棵樹開始深度優先搜尋.
我們在走出以 u u 為根的子樹時必須要保證走完的整棵子樹通過的次數都滿足要求的奇偶性,因為我們再也不會走進這棵子樹了.
這樣我們對這棵樹跑一次尤拉序,能夠保證子節點都走過奇數次,父節點 u u 走過的次數的奇偶性不變.
如果 u u 的奇偶性不滿足,就走到它的父親再走回來,這樣 u u 和它的子樹都滿足了條件,回去解決它的父節點即可.
注意 d f s dfs 完之後只有根節點因為沒有父節點能夠幫助它,所以有可能擺脫不了奇偶性不正確的宿命,這時候只要我們幫助它特判一下它的奇偶性是否已經正確,如果不正確,把遍歷路徑的最後一個點刪掉(肯定是根節點)即可.
最後是證明這樣的路徑肯定不超過 4 × n 4\times n 個點.
很明顯尤拉序的長度不超過 2 × n 2\times n ,每一個點判父節點增加的路徑長度是 2 2 ,總長不超過 4 × n 4\times n .
這樣就可以通過此題了.

#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rel register ll
#define rec register char
#define gc getchar
//#define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<23,stdin),p1==p2)?-1:*p1++)
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
char buf[1<<23],*p1=buf,*p2=buf;
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) pc('-'),x=-x;
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e5;
typedef int fuko[yuzu|10];
vector<int> lj[yuzu|10],ph;
fuko tov,vis;

#define atp(u) ph.push_back(u),tov[u]^=1
void dfs(int u,int fa=0) {
vis[u]=1,atp(u);
for (int v:lj[u]) if (!vis[v]) 
  dfs(v,u),atp(u);
if (tov[u]&&fa) atp(fa),atp(u);
if (tov[u]) ph.pop_back();
}

bool judge(int n){
int i,hoc=0; // 統計有多少個含奇數度點的連通塊.
static fuko vs;
for (i=1;i<=n;++i) if (!vs[i]) {
  int bo=0;
  queue<int> q; vs[i]=1,q.push(i);
  for (;!q.empty();) {
    int u=q.front(); q.pop();
    if (tov[u]) bo=1;
    for (int v:lj[u]) if (!vs[v]) vs[v]=1,q.push(v);
    }
  hoc+=bo;
  }return hoc<=1;
}

int main() {
int i,n,m,u,v;
read(n),read(m);
for (i=1;i<=m;++i)
  u=read(),v=read(),
  lj[u].push_back(v),
  lj[v].push_back(u);
for (i=1;i<=n;++i) tov[i]=read();
if (!judge(n)) return puts("-1"),0;
for (i=1;i<=n;++i) if (!vis[i]&&tov[i]) dfs(i);
cout<<ph.size()<<endl;
for (auto p:ph) write(p),p32;
}