The Tour

Description

明天就要和所有M&F成员去唐山旅游了,但是SF面馆特派员还有N件事情没有做完成,做这件事还有M个限制条件,每个限制条件均为:事件A必须在事件B之前完成。现在SF面馆特派员想知道做完这N件事一共有多少种方法。

Input

第一行两个整数N,M。接下来M行,每行两个数Ai,Bi,表示事件Ai必须在Bi之前完成。

Output

一个整数,完成N件事共有多少种方法。

Sample Input

3 2
1 3
2 3

Sample Output

2

Hint

N≤17; M≤400; 1S; 256M

题解

\(N≤17\)的数据着实有些小,于是我们就可以用位运算。用二进制来记录状态,\(1\)表示未选(或可选),\(0\)表示已选,\(f[]\)表示该状态的方案数,加上记忆化后貌似跑得更快,最后加上拓扑排序的模板即可。

#include<iostream>
#include<cstdio>
using namespace std;

const int N=20,M=500,N2=1<<18;
int n,m,nout[N],in[N],out[N][M];
long long f[N2];

void Dfs(int nw)
{
	if(f[nw]) return;
	int YH;
	for(int i=1;i<=n;++i)
		if((!in[i])&&(nw&(1<<(i-1))))//可选
		{
			YH=nw&(~(1<<(i-1)));//选
			for(int j=1;j<=nout[i];++j) --in[out[i][j]];
			Dfs(YH);
			for(int j=1;j<=nout[i];++j) ++in[out[i][j]];
			f[nw]+=f[YH];
		}
}

int main()
{
	scanf("%d%d",&n,&m);
	int a,b;
	for(int i=1;i<=m;++i)
		scanf("%d%d",&a,&b),
		++nout[a],out[a][nout[a]]=b,++in[b];
	int YH=(1<<n)-1;
	f[0]=1;
	Dfs(YH),
	cout<<f[YH]<<endl;
	return 0;
}
posted @ 2019-08-22 10:00  OItby  阅读(141)  评论(0编辑  收藏  举报