#include <iostream>
#include <vector>
#include <set>
#include <assert.h>
#include <cmath>
#include <map>
#include <complex>
#include <gmpxx.h>
#include <algorithm>
//In this we described different "automatons" each of them is a class that contains the methods necessary to compute the operators
using namespace std;

int gcd(int a, int b){
  if(a<b) return gcd(b,a);
  else if(b==0) return a;
  else return gcd(b,a%b);    
}

int lcm(int a, int b){
  return a*b/gcd(a,b);
}

//This class is initialized with the sets sigma and rho and computes all the (sigma,rho) dominating sets 
struct automaton_All{
  pair<int,int>  gD;//automaton
  pair<int,int> gF;
  vector<bool> fD;//accepting set
  vector<bool> fF;
  vector<int> baseVect;
  vector<int> base;
  size_t size_Aut;
  int D;
  int d;
  
  automaton_All(pair<int,int>& tgD, vector<bool> tfD, pair<int,int>& tgF, vector<bool> tfF):gD(tgD), gF(tgF), fD(tfD), fF(tfF), baseVect(gD.first+gF.first,0){
    D = gD.first;
    d = gF.first;
    size_Aut = D+d;
    baseVect[0] = baseVect[D] = 1;
    base.push_back(0);
    base.push_back(D);
  }
  
  int Dincr(int n){
    if(n==-1) return -1; 
    if(n<D){
      n++;
      if(n == gD.first) n = gD.second;
    }else{
      n = (n-D)+1; 
      if(n == gF.first) n = gF.second;
      n += D;
    }
    return n;
  }
  
  bool canBeForgoten(int n){
    if(n==-1) return false; 
    if(n<D) return fD[n];
    else return fF[n-D];
  }
  
  int forgetSecondAfterOneEdge(int n, int m){
    if(n<D) m = Dincr(m);
    if(m<D) n = Dincr(n);
    if(canBeForgoten(m)) return n;
    else return -1;    
  }
  pair<int,int> forgetThirdAfterTwoEdges(int a, int b, int c){
    if(a<D) c = Dincr(c);
    if(b<D) c = Dincr(c);
    if(c<D){ a = Dincr(a); b = Dincr(b); }
    if(canBeForgoten(c)) return pair<int,int>(a,b);
    else return pair<int,int>(-1,-1);    
  }
};

//This class is initialized with the sets sigma and rho and computes the 1-minimal (sigma,rho) dominating sets 
class automaton1Min{
public:
  pair<int,int>  g; //automaton that counts the number of D seen other than himself, first = number of states, second = state to jump back from state first-1
  bool* fD; //accepting set
  bool* fF;
  
  //The states are represented by an integer and there are 6 possibilities
  //in the comments of the next lines S is the sum of the previous integers
  int Dhasandis;// state between 0 and Dhasandis-1 if it is in D and has and is a certificate
  int Dhascertisnot;// state between S and S+Dhascertisnot-1 if it is in D and has but is not a certificate
  int Dneedcertis;// state between S and S+Dneedcertis-1 if it is in D and is a certificate but has no certificate
  int Dneedcertisnot;// state between S and S+Dneedcertisnot-1 if it is in D and is not a certificate and has no certificate
  int dis;// state between S and S+dis-1 if it is not in D and is a certificate
  int disnot;// state between S and S+disnot-1 if it is not in D and is not a certificate
  vector<int> baseVect;
  vector<int> base;
  int size_Aut;
  
  automaton1Min(pair<int,int>& tgD, vector<bool> tfD, pair<int,int>& tgF, vector<bool> tfF){
    g= pair<int,int>(max(tgD.second, tgF.second) + lcm(tgD.first-tgD.second, tgF.first-tgF.second), max(tgD.second, tgF.second));
    fD = (new bool[g.first+2])+1;
    fF = (new bool[g.first+2])+1;
    for(int i=0, j=0, k=0; i<g.first; i++,j++,k++){
      if(j == tgD.first) j = tgD.second;
      if(k == tgF.first) k = tgF.second;
      fD[i] = tfD[j];
      fF[i] = tfF[k];      
    }
    if(g.second == 0){ fD[-1] = fD[g.first-1]; fF[-1] = fF[g.first-1]; }
    if(fD[g.first-1] != fD[g.second-1] || fF[g.first-1] != fF[g.second-1]){
      fF[g.first] = fF[g.second];
      fD[g.first] = fD[g.second];
      g.first++; g.second++;
    }
    Dhasandis =  Dhascertisnot = Dneedcertisnot =  Dneedcertis = dis = disnot = g.first;
    size_Aut = 6* g.first;
    
    baseVect=vector<int>(size_Aut,0);
    baseVect[Dhasandis + Dhascertisnot] = 1;
    baseVect[Dhasandis + Dhascertisnot+Dneedcertis] = 1;
    baseVect[Dhasandis + Dhascertisnot+Dneedcertis+Dneedcertisnot] = 1;
    baseVect[Dhasandis + Dhascertisnot+Dneedcertis+Dneedcertisnot+ dis] = 1;
    for(size_t i=0;i<baseVect.size();i++) if(baseVect[i] !=0) base.push_back(i);
  }
  
  int Dincr(int n){
    if(n==-1) return -1; 
    int m = n%g.first;
    n = (n-m);
    m++;
    if(m == g.first) m = g.second;
    return n+m;
  }
  
  int getacert(int n){ 
    if(n >= Dhasandis + Dhascertisnot && n<Dhasandis + Dhascertisnot+Dneedcertis) 
      return n-Dhasandis - Dhascertisnot;
    else if(n >= Dhasandis + Dhascertisnot+Dneedcertis && n<Dhasandis + Dhascertisnot+Dneedcertis+Dneedcertisnot) 
      return n- Dhascertisnot-Dneedcertis;
    else return n;
  }
  
  bool canBeForgoten(int n){
    if(n==-1) return false; 
    if(n<Dhasandis) return (fD[n] && !fD[n-1]);
    else{
      n-=Dhasandis;
      if(n<Dhascertisnot) return fD[n] && fD[n-1];
      else{
        n-=Dhascertisnot;
        if(n<Dneedcertis) return(fD[n] && !fD[n-1] && !fF[n]);
        else{
          n-=Dneedcertis;
          if(n<Dneedcertisnot) return (fD[n]&& fD[n-1] && !fF[n]);
          else{
            n-=Dneedcertisnot;
            if(n<dis)  return (fF[n] && !fF[n-1]);
            else{
              n-=dis;
              return (fF[n] && fF[n-1]);
            }
          }
        }
      }
    }
  } 
  
  bool isInD(int n){
    return (n<Dhasandis+Dhascertisnot+Dneedcertis+Dneedcertisnot);
  }
  
  bool isCert(int n){
    return (n<Dhasandis)|| (n>=Dhasandis+Dhascertisnot && n<Dhasandis+Dhascertisnot+Dneedcertis)
    ||(n>=Dhasandis+Dhascertisnot+Dneedcertis+Dneedcertisnot && n<Dhasandis+Dhascertisnot+Dneedcertis+Dneedcertisnot+dis);
  }
  
  int forgetSecondAfterOneEdge(int n, int m){
    if(isInD(n)) m = Dincr(m);
    if(isInD(m)) n = Dincr(n);
    if(isCert(m)) n = getacert(n);
    if(isCert(n)) m = getacert(m);
    if(canBeForgoten(m)) return n;
    else return -1;    
  }
  
  pair<int,int> forgetThirdAfterTwoEdges(int a, int b, int c){
    if(isInD(a)) c = Dincr(c);
    if(isInD(b)) c = Dincr(c);
    if(isInD(c)){ a = Dincr(a); b = Dincr(b); }
    if(isCert(a)) c = getacert(c);
    if(isCert(b)) c =getacert(c);
    if(isCert(c)){ a = getacert(a); b = getacert(b); }
    if(canBeForgoten(c)) return pair<int,int>(a,b);      
    return pair<int,int>(-1,-1);
  }
  
  ~automaton1Min(){
    delete[] (fD-1);
    delete[] (fF-1);
  }  
};

//This class is initialized with the sets sigma and rho and computes the 1-maximal (sigma,rho) dominating sets 
class automaton1Max{
public:
  pair<int,int>  g; //automaton that counts the number of D seen other than himself, first = number of states, second = state to jump back from state first-1
  bool* fD; //accepting set for sigma
  bool* fF;//accepting set for rho
  
   //The states are represented by an integer and there are 6 possibilities
  //In the comments of the next lines S is the sum of the previous integers
  int Dis; // state between 0 and Dis-1 if it is in D and is a certificate
  int Disnot;// state between S and S+Disnot-1 if it is in D and is not a certificate
  int dhasandis;// state between S and S+ dhasandis-1 if it is not in D and has and is a certificate
  int dhasandisnot;// state between S and S+dhasandisnot-1 if it is not in D and has a certificate but is not a certificate
  int dneedsandis;// state between S and S+needsandis-1 if it is  notin D and, has no certificate but is  a certificate
  int dneedsandisnot;// state between S and S+dneedsandisnot-1 if it is not in D, is not a certificate and has no certificate
  vector<int> baseVect;
  vector<int> base;
  int size_Aut;
  
  automaton1Max(pair<int,int>& tgD, vector<bool> tfD, pair<int,int>& tgF, vector<bool> tfF){
    g= pair<int,int>(max(tgD.second, tgF.second) + lcm(tgD.first-tgD.second, tgF.first-tgF.second), max(tgD.second, tgF.second));
    fD= new bool[g.first+1];
    fF= new bool[g.first+1];
    for(int i=0, j=0, k=0; i<g.first+1; i++,j++,k++){
      if(j==tgD.first) j = tgD.second;
      if(k==tgF.first) k = tgF.second;
      fD[i]=tfD[j];
      fF[i]=tfF[k];      
    }
    Dis = Disnot = dhasandis = dhasandisnot = dneedsandis = dneedsandisnot = g.first;
    size_Aut = Dis + Disnot + dhasandis + dhasandisnot + dneedsandis + dneedsandisnot;
        
    baseVect=vector<int>(size_Aut,0);
    baseVect[0]=1;
    baseVect[Dis]=1;
    baseVect[Dis + Disnot + dhasandis + dhasandisnot]=1;
    baseVect[Dis + Disnot + dhasandis + dhasandisnot + dneedsandis]=1;
    for(size_t i=0;i<baseVect.size();i++) if(baseVect[i]!=0)base.push_back(i);
  }
  
  int Dincr(int n){
    if(n==-1) return -1; 
    int m = n%g.first;
    n = (n-m);
    m++;
    if(m == g.first) m = g.second;
    return n+m;
  }
  
  int getacert(int n){ 
    if(n >= Dis + Disnot + dhasandis + dhasandisnot  && n<Dis + Disnot + dhasandis + dhasandisnot+ dneedsandis) return n - dhasandis - dhasandisnot;
    else if(n >= Dis + Disnot + dhasandis + dhasandisnot + dneedsandis) return n - dhasandisnot - dneedsandis;
    else return n;
  }
  
  bool canBeForgoten(int n){
    if(n==-1) return false; 
    if(n<Dis) return (fD[n] && !fD[n+1]);
    else{
      n-=Dis;
      if(n<Disnot) return (fD[n] && fD[n+1]);
      else{
        n-=Disnot;
        if(n<dhasandis) return (fF[n] && !fF[n+1]);
        else{
          n-=dhasandis;
          if(n<dhasandisnot) return (fF[n] && fF[n+1]);
          else{
            n-=dhasandisnot;
            if(n<dneedsandis) return (fF[n] & !fF[n+1]  && !fD[n]);
            else{
              n-= dneedsandis;
              return (fF[n] & fF[n+1]  && !fD[n]);
            }
          }
        }
      }
    }
  }
  bool isInD(int n){
    return (n< Dis + Disnot);
  }
  bool isCert(int n){
    return (n<Dis)|| (n>=Dis + Disnot && n<Dis + Disnot + dhasandis)
    ||(n>=Dis + Disnot + dhasandis + dhasandisnot  && n<Dis + Disnot + dhasandis + dhasandisnot + dneedsandis);
  }
   
  int forgetSecondAfterOneEdge(int n, int m){
    if(isInD(n)) m = Dincr(m);
    if(isInD(m)) n = Dincr(n);
    if(isCert(m)) n = getacert(n);
    if(isCert(n)) m = getacert(m);
    if(canBeForgoten(m)) return n;
    else return -1;      
  }
  
  pair<int,int> forgetThirdAfterTwoEdges(int a, int b, int c){
    if(isInD(a)) c = Dincr(c);
    if(isInD(b)) c = Dincr(c);
    if(isInD(c)){ a = Dincr(a); b = Dincr(b); }
    if(isCert(a)) c = getacert(c);
    if(isCert(b)) c = getacert(c);
    if(isCert(c)){ a = getacert(a); b = getacert(b); }
    if(canBeForgoten(c)) return pair<int,int>(a,b);      
    return pair<int,int>(-1,-1);
  }
  
  ~automaton1Max(){
    delete[] (fD);
    delete[] (fF);
  }  
};

//This class computes the maximal induced matching 
class automatonMaxInducedMatching{
public:
  vector<int> baseVect;
  vector<int> base;
  int size_Aut;
  
  automatonMaxInducedMatching(){
    size_Aut = 5;
    baseVect=vector<int>(size_Aut,0);
    baseVect[0]=baseVect[2]=1;
    for(size_t i=0;i<baseVect.size();i++) if(baseVect[i] != 0) base.push_back(i);
  }
  
  int Dincr(int n){
    if(n == 0) return 1;
    if(n == 1) return -1;
    if(n == 2 || n == 3|| n == 4) return 4;
  }
  
  int Fincr(int n){
    if(n == 2) return 3;
    else return n;
  }
  
  bool canBeForgoten(int n){
    if(n == 1 || n == 2 || n == 4) return true;
    else return false;
  }
  
  bool isInD(int n){
    return (n< 2);
  }
   
  int forgetSecondAfterOneEdge(int n, int m){
    if(isInD(n)) m = Dincr(m);
    if(isInD(m)) n = Dincr(n);
    if(canBeForgoten(m)){
      if(m == 2) return Fincr(n);
      else return n;      
    }
    else return -1;      
  }
  
  pair<int,int> forgetThirdAfterTwoEdges(int a, int b, int c){
    if(isInD(a)) c = Dincr(c);
    if(isInD(b)) c = Dincr(c);
    if(isInD(c)){ a = Dincr(a); b = Dincr(b);}
    if(canBeForgoten(c)){
      if(c == 2) return pair<int,int>(Fincr(a),Fincr(b));
      else return pair<int,int>(a,b);
    }
    else return pair<int,int>(-1,-1);
  }
};

//This class computes the minimal dominating set with a special state 36 which means "at least one of the two vertices is a certificate"
//Any entry of the operator related to this special state is handeld in the function using this class
class automatonminDomPart{
public:
  vector<int> baseVect;
  vector<int> base;
  int size_Aut;
  
  automatonminDomPart(){
    size_Aut = 6;
    baseVect=vector<int>(size_Aut,0);
    baseVect[1]=baseVect[5]=1;
    for(size_t i=0;i<baseVect.size();i++) if(baseVect[i] != 0) base.push_back(i);
  }
  
  bool canBeForgoten(int n){
    if(n == 0 || n == 1 || n == 3 || n == 4) return true;
    else return false;
  }
  
  int getCert(int n){
    if(n == 1 || n == 2) return 0;
    else return n;
  }
  
  int casttoCert(int n){
    if(n == 5) return 3;
    else return -1;
  }
  
  int Dincr(int n){
    if(n == 1) return 2;
    else if(n == 3) return -1;
    else if(n == 5) return 4;
    else return n;
  }
  
  bool isInD(int n){
    return (n< 3);
  }
   
  int forgetSecondAfterOneEdge(int n, int m){
    if(isInD(n)){
      if(isInD(m)){
        if(canBeForgoten(Dincr(m))) return Dincr(n);
        else return -1;
      }else{
        if(canBeForgoten(Dincr(m)) && canBeForgoten(m)) return n;   
        else if(canBeForgoten(Dincr(m)) && !canBeForgoten(m)) return getCert(n);  
        else return -1;
      }
    }else{
      if(isInD(m)){
        if(canBeForgoten(m)) return Dincr(n);
        else if(canBeForgoten(getCert(m))) return casttoCert(n);
        else return -1;
      }else{
        if(canBeForgoten(m)) return n;
        else return -1;
      }
    }
  }
  
  pair<int,int> forgetThirdAfterTwoEdges(int a, int b, int c){
    if(isInD(c)){
      if(c == 0 ||(c == 1 && (!isInD(a)) && (!isInD(b))) ) return pair<int,int>(Dincr(a), Dincr(b));
      else{//c needs a certificate
        if(a != 5) return pair<int,int>(Dincr(a), casttoCert(b));
        else if(b != 5) return pair<int,int>(casttoCert(a), Dincr(b));
        else return pair<int,int>(-1,-1);// if a=b=5 then we should end up in stat 37 this is handeld in the operator file
      }
    }else{
      if(isInD(a) && isInD(b)){
        if(canBeForgoten(Dincr(c)))
          return  pair<int,int>(a,b);
        else return pair<int,int>(-1,-1);
      }else if(isInD(a)){
        if(c == 5) return pair<int,int>(getCert(a),b);
        else if(c == 4) return pair<int,int>(a,b);
        else return pair<int,int>(-1,-1);
      }else if(isInD(b)){
        if(c == 5) return pair<int,int>(a,getCert(b));
        else if(c == 4) return pair<int,int>(a,b);
        else return pair<int,int>(-1,-1);
      }else{
        if(canBeForgoten(c)) return pair<int,int>(a,b);
        else return pair<int,int>(-1,-1);
      }
    }    
  }
};


