JZYZOJ 1388 旅游 状压dp

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\n",f[ma-1]);
30     return 0;
31 }
View Code

 

posted @ 2017-11-05 11:53  鲸头鹳  阅读(179)  评论(0编辑  收藏  举报