競技プログラミング日記

主に AtCoder の記事です

AtCoder Beginner Contest 041D

D - 徒競走


トポロジカルソートの場合の数を数え上げる問題.
これはDPで可能.


 Sを頂点集合の部分集合とする.
 dp_{S} = Sをトポロジカルソートする場合の数,
 X_{S}を, Sの元のうち,出次数が0の頂点全体
とする.
 X_{S}の元  vに関して場合分けして数え上げる.
 vを一番端にもってくる場合の数は dp_{S - \{v\}}となる.

よって,
 dp_{S} = 1 \ (if \ S = \emptyset), \\ \sum_{v \in X_{S}} dp_{S-\{v\}} \ (otherwise)
という遷移で求まる.

typedef long long ll;
using vll = vector<long long>;  using vvll = vector<vll>;
#define srep(i,s,t) for (ll i = (s); i < (t); ++i)
#define rep(i,n) srep(i,0,(n))

int main() {
    ll n,m; cin >> n >> m;
    vvll to(n);
    rep(i,m){
        ll a, b; cin >> a >> b;
        --a, --b;
        to[a].push_back(b);
        //to[b].push_back(a);
    }
   
    vll dp(1LL<<n);
    dp[0] = 1;
    rep(s,1LL<<n) if(s){
        rep(i,n) if(s>>i&1){

            bool f = true;
            fore(x, to[i]){
                if(s>>x&1) f = false;

            }
            if(f) {
                ll t = s ^ (1LL<<i);
                dp[s] += dp[t];
            }
        }
    }
    cout << dp[(1LL<<n)-1] << endl;

    return 0;
}