AtCoder Beginner Contest 244 G - Construct Good Path (DFS、构造)
AtCoder Beginner Contest 244 G - Construct Good Path
题意
在一张 \(n\) 个点 \(m\) 条无向边组成的图中找到一条长度不超过 \(4K\) 的路径
再给定字符串 \(S\),如果 \(S_i=1\),则找出的这条路径中点 \(i\) 出现的次数必须是奇数次,反之必须是偶数次
输出任意一条符合情况的路径
思路
考虑任意找一个点为根,删除一些边使得图变成一张生成树(较为好看,也好处理),这里我找了任意一个 \(S_{root}=1\) 的 \(root\) 点作为根
首先 \(dfs\) 处理出这个生成树,存图
其后再 \(dfs\) 一次,维护一个 \(bool\) 数组 \(needDFS\),如果 \(i\) 点及其子树中存在任意一个点 \(j\) 满足 \(S_j=1\),那么 \(needDFS[i]=true\)
根据以上处理,最后我们从 \(root\) 点重新出发 \(dfs\) 第三遍,开始寻找答案
因为需要保证 \(S_p=0\) 的那些点访问偶数次,而过程中肯定是需要经过这些点的,所以这里根据 dfs 序的想法,从根节点搜索下去,再返回,这样经过两次来保证偶数次,其余特殊情况下面再处理,这里只是想法来源的说明
假设当前搜索到了点 \(u\),将点 \(u\) 加入答案队列,然后枚举它的所有子节点 \(v\),只要 \(needDFS[v]=true\),就继续搜索点 \(v\)
注意,如果这里对子节点 \(v\) 进行了搜索,则从子树返回的时候需要再将点 \(u\) 加入答案队列来保证路径的连通,然后继续再看其他子节点
最后,处理完点 \(u\) 的所有子节点后,这里就需要返回了,之后就不再看点 \(u\) 及其子树了,因此在返回之前需要检查一下是否此时点 \(u\) 的访问次数奇偶性满足条件了
- 如果已经满足条件,则直接返回上一层父节点继续 \(dfs\) 即可
- 如果没有,因为这里假设子树的访问次数已经符合题意了,所以拿点 \(u\) 及其父节点与其刷步数,按顺序将点 \(u\) 的父节点 \(fa\) 加入队列,再将点 \(u\) 加入队列一次,这样点 \(u\) 的访问次数的奇偶性就改变了
- 需要注意的是,如果当前点 \(u\) 已经是根节点,没有父节点,就不能这样做,反之,这种情况下答案序列的最后一个点一定是点 \(u\),因此将队列尾的点 \(u\) pop掉就可以,表示路径就不返回根节点了
程序
// Problem: G - Construct Good Path
// Contest: AtCoder - AtCoder Beginner Contest 244
// URL: https://atcoder.jp/contests/abc244/tasks/abc244_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Author: StelaYuri
// Import Time: 2022-03-20 20:54:20.532
//
// Powered by CP Editor (https://cpeditor.org)
// Template Ver.220227
//#include<bits/stdc++.h>
#include<algorithm>
#include<cctype>
#include<chrono>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<functional>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<random>
#include<set>
#include<sstream>
#include<stack>
#include<string>
#include<utility>
#include<vector>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(auto i=(a);i<=(b);i++)
#define repp(i,a,b) for(auto i=(a);i<(b);i++)
#define per(i,a,b) for(auto i=(a);i>=(b);i--)
#define perr(i,a,b) for(auto i=(a);i>(b);i--)
#define REP(i,a,b,s) for(auto i=(a);i<=(b);i+=(s))
#define REPP(i,a,b,s) for(auto i=(a);i<(b);i+=(s))
#define PER(i,a,b,s) for(auto i=(a);i>=(b);i-=(s))
#define PERR(i,a,b,s) for(auto i=(a);i>(b);i-=(s))
#define all(a) (a).begin(),(a).end()
#define mst(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define eb emplace_back
#define YES cout<<"Yes\n"
#define NO cout<<"No\n"
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
namespace BasicTemplate{
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int dx[8]={0,1,0,-1,1,1,-1,-1},dy[8]={1,0,-1,0,1,-1,1,-1};
const ll mod=998244353;
mt19937 mtrandom(std::chrono::system_clock::now().time_since_epoch().count());
ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mtrandom);}
void debug(){cerr<<'\n';}template<typename T,typename... Args>void debug(T x,Args... args){cerr<<"[ "<<x<< " ] , ";debug(args...);}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}
}
namespace FastIO{
const int bsz=1<<18;char bf[bsz],*head,*tail;
inline char gc(){if(head==tail)tail=(head=bf)+fread(bf,1,bsz,stdin);if(head==tail)return 0;return *head++;}
inline int read(){int x=0,f=1;char c=gc();for(;!isdigit(c);c=gc())if(c=='-')f=-1;for(;isdigit(c);c=gc())x=x*10+c-'0';return x*f;}
inline ll read64(){ll x=0,f=1;char c=gc();for(;!isdigit(c);c=gc())if(c=='-')f=-1;for(;isdigit(c);c=gc())x=x*10+c-'0';return x*f;}
inline void print(int x){if(x>9)print(x/10);putchar(x%10+'0');}
inline void println(int x){print(x);putchar('\n');}
inline void print(ll x){if(x>9)print(x/10);putchar(x%10+'0');}
inline void println(ll x){print(x);putchar('\n');}
}
using namespace BasicTemplate;
//using namespace FastIO;
int n,m;
int dep[100050];
vector<int> G[100050];
vector<int> GG[100050];
char s[100050];
bool needDFS[100050];
int odd[100050];
void dfsdep(int u,int fa)
{
dep[u]=dep[fa]+1;
for(int &v:GG[u])
{
if(dep[v]==0)
{
G[u].pb(v);
dfsdep(v,u);
}
}
}
bool dfsodd(int u,int fa)
{
needDFS[u]=odd[u];
for(int &v:G[u])
{
if(dfsodd(v,u))
needDFS[u]=true;
}
return needDFS[u];
}
vector<int> ans;
int sta[100050];
void dfs(int u,int fa)
{
//cout<<fa<<' '<<u<<'\n';
ans.pb(u);
sta[u]^=1;
for(int &v:G[u])
{
if(!needDFS[v])
continue;
dfs(v,u);
ans.pb(u);
sta[u]^=1;
}
if(sta[u]!=odd[u])
{
if(fa==0)
{
ans.pop_back();
sta[u]^=1;
return;
}
else
{
ans.pb(fa);
ans.pb(u);
sta[fa]^=1;
sta[u]^=1;
}
}
}
void solve()
{
cin>>n>>m;
rep(i,1,m)
{
int a,b;
cin>>a>>b;
GG[a].pb(b);
GG[b].pb(a);
}
cin>>(s+1);
int pos=0;
rep(i,1,n)
{
odd[i]=(s[i]=='1');
if(odd[i])
pos=i;
}
if(pos==0)
{
cout<<0<<'\n';
return;
}
dfsdep(pos,0);
dfsodd(pos,0);
dfs(pos,0);
cout<<ans.size()<<'\n';
for(int i:ans)
cout<<i<<' ';
}
signed main()
{
closeSync;
//multiCase
{
solve();
}
return 0;
}