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;
}

posted @ 2022-03-20 21:47  StelaYuri  阅读(132)  评论(0编辑  收藏  举报