http://172.20.6.3/Problem_Show.asp?id=1388
求拓扑排序方案数 状压dp,最开始以为是拓扑排序加数论或者搜索,没想到是状压dp,突然气死.jpg;
完全没有想到状态转移的方法,syq大佬太神了orz;
写的时候太沉迷与topsort对人顺序的分组类似于斯特林数求方案数(后来发现不是),忘了最原始的满足条件(事件a在事件b前完成)即可增加方案数的简单dp……(惭愧)
所以正解就是按dp进行顺序向状态里加人,对人实现排序,显然如果必须在a前的人都加到队列里了(我这里用的是a后,嗯因为写的时候是直接看syq大佬的代码,其实我觉得记录a前的更符合逻辑)那么a就可以放到这个队列后面了。
据此,f[i]表示状态i(i上为1的位表示这一位的人放到队列里了)有多少种方案,a[x]表示x需要哪些人在前面(我写的用的是后面,毕竟从后往前和从前往后并没有什么区别…)。
第一次交爆了long long,果然long long是1A率的拦路虎,努力克服
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 const int maxn=30; 9 int n,m; 10 int a[maxn]={}; 11 long long f[(1<<17)+10]={}; 12 int main(){ 13 scanf("%d%d",&n,&m);int x,y; 14 for(int i=1;i<=m;i++){ 15 scanf("%d%d",&x,&y); 16 a[x]|=(1<<(y-1)); 17 } 18 int ma=1<<n;f[0]=1; 19 for(int i=1;i<ma;i++){ 20 for(int j=0;j<n;j++){ 21 if((1<<j)&i){ 22 y=i-(1<<j); 23 if((a[j+1]&(~y))==0){ 24 f[i]+=f[y]; 25 } 26 } 27 } 28 } 29 printf("%I64d ",f[ma-1]); 30 return 0; 31 }