Naomi's notebook

Naomi's notebook

union-find(ARC069D - Menagerie)

atcoder.jp

朝の電車の中で10分くらい考察して、あとは実装した。


大切なのは「ある2箇所の動物が決まると、その次の動物も決まる」と言うこと。
まず、可能かどうかを調べる。場所二つごとに羊と狼の組み合わせ(2^2=4通り)を要素としてunion-findを行い、一周した時に矛盾していないか(Nと1のペアのrootと1と2のペアのrootが一致しているか)確かめれば良い。


unionできる組み合わせの条件は
①同じ場所の動物が同じ(前の組の二個目=後の組の一個目)
②oと×の条件に一致している

羊と狼のパターンの出力は、N番目の動物から、最終的に正しい1番目の動物にたどり着くように、逆に辿って行けば良い(ここもう少し簡単に書けるような気がする…ここですごく時間がかかった…)

#include<cstdio>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<string>
#include<set>
#include<cstring>
 
using namespace std;
#define rep(i,n) for(int i=0;i<n;i++)
#define INF 1001001001
#define LLINF 1001001001001001001
#define mp make_pair
#define pb push_back
#define LLIandI pair<long long int , int>
#define ll long long

//union find
struct union_find{
    int *parent; //parent[i]=parent of i
    int N;
    union_find(int N):N(N){
        parent=new int[N];
        rep(i,N)parent[i]=i; //init
    }
    int root(int x){ // take the root of x 
        if(parent[x]==x) return x;
        parent[x]=root(parent[x]); // recursion
        return parent[x];
    }
    void unite(int x,int y){// unite tree y to tree x
        int rx=root(x);
        int ry=root(y);
        if(rx==ry) return;
        parent[ry]=rx;
    }
    bool same(int x,int y){
        int rx=root(x);
        int ry=root(y);
        return rx==ry;
    }
    bool IsAllSameTree(){
        int rt=parent[0];
        rep(i,N){
            if(rt!=parent[i])return false;
        }
        return true;
    }
};

int main(){
    int N;char s[100004];
    scanf("%d",&N);
    scanf("%s",&s);
    union_find uf((N+1)*4);
    //iとi+1番目のペア…i*4+a (a:羊羊=0 羊狼=1 狼羊=2 狼狼=3)
    rep(i,N-1){
        if(s[i+1]=='o'){
            uf.unite(i*4+0,(i+1)*4+0);
            uf.unite(i*4+1,(i+1)*4+3);
            uf.unite(i*4+2,(i+1)*4+1);
            uf.unite(i*4+3,(i+1)*4+2);
        }else{
            uf.unite(i*4+0,(i+1)*4+1);
            uf.unite(i*4+1,(i+1)*4+2);
            uf.unite(i*4+2,(i+1)*4+0);
            uf.unite(i*4+3,(i+1)*4+3);
        }
    }
    int parent=-1;int end=-1;char ans[100004];
    if(s[0]=='o'){
        if(uf.root((N-1)*4+0)==0){parent=uf.root(0);end=0;}
        if(uf.root((N-1)*4+1)==3){parent=uf.root(3);end=1;}
        if(uf.root((N-1)*4+2)==1){parent=uf.root(1);end=2;}
        if(uf.root((N-1)*4+3)==2){parent=uf.root(2);end=3;}
    }else{
        if(uf.root((N-1)*4+0)==1){parent=uf.root(1);end=0;}
        if(uf.root((N-1)*4+1)==2){parent=uf.root(2);end=1;}
        if(uf.root((N-1)*4+2)==0){parent=uf.root(0);end=2;}
        if(uf.root((N-1)*4+3)==3){parent=uf.root(3);end=3;}
    }
    if(parent==-1){printf("-1\n");return 0;}
    if(end<2)ans[N-1]='S';
    else ans[N-1]='W';
    for(int i=N-2;i>-1;i--){
       if(s[i+1]=='o'){
           if(ans[i+1]=='S'&&uf.root(i*4+0)==parent){ans[i]='S';continue;}
           if(ans[i+1]=='S'&&uf.root(i*4+2)==parent){ans[i]='W';continue;}
           if(ans[i+1]=='W'&&uf.root(i*4+3)==parent){ans[i]='W';continue;}
           if(ans[i+1]=='W'&&uf.root(i*4+1)==parent){ans[i]='S';continue;}
        }else{
            if(ans[i+1]=='S'&&uf.root(i*4+0)==parent){ans[i]='S';continue;}
            if(ans[i+1]=='S'&&uf.root(i*4+2)==parent){ans[i]='W';continue;}
            if(ans[i+1]=='W'&&uf.root(i*4+1)==parent){ans[i]='S';continue;}
            if(ans[i+1]=='W'&&uf.root(i*4+3)==parent){ans[i]='W';continue;}
        }
    }
    ans[N]='\0';
    printf("%s\n",ans);
}