競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 310D

ABC310D

\(N,M,T\) がいずれも小さいので,全探索して数えても間に合いそう. DFS によりすべて列挙する. このとき,取りこぼしと重複が無いようにする. 今回は起こらなかったが,仮に重複するのなら,その分を割ることにする.
実装
先に \(T\) 個の入れ物 \(v[i] \ (i \in T)\) を用意して,そこに人 \(i \in N \) を割り当てていく. 重複しないために, 空の \(v[i]\) が複数あってそれを使うときは, 一番 \(i\) の小さい物を使うというルールにする.
また,DFS で潜る前に変更した部分を, DFS の潜りから帰った後に戻す.
終了条件と遷移を分けて書くと楽. DFS の深さ \(i\) において,人 \(i \in N\) の割り当てを決める.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll n, t, m ;
  cin >> n >> t >> m;

  vll a(m), b(m);
  rep(i,m){
    cin >> a[i] >> b[i];
    a[i]--, b[i]--;
  }

  vvll v(t);
  ll ans = 0;
  auto f = [&](auto f, ll i = 0) -> void {
    if(i == n){
      rep(j,t) rep(k,m){
        if(in(a[k], v[j]) && in(b[k], v[j])) return;
      }

      rep(j,t) if(v[j].size() == 0) return;

      ans++;
      return;
    }
   
    bool g = false;
    rep(j,t) if(!g){
      if(v[j].size() == 0) g = true;
      v[j].push_back(i);
      f(f, i+1);
      v[j].pop_back();
    }

  };
 
  f(f);
  cout << ans << endl;  


  return 0;
}