ZJU 1346 Comparing Your Heroes 状态压缩DP 拓扑排序的计数

做多校的时候遇见一个求拓扑排序数量的题,就顺便来写了一下。

题意:

  你有个朋友是KOF的狂热粉丝,他有一个对其中英雄的强弱比较,让你根据这些比较关系来给这些英雄排名。问一共有多少种排名方式。

思路:

  用dp[S]记录当前状态的数量。 S表示拓扑排序中当前阶段已经被排序的点的集合。然后就可以枚举当前排序的点,转移的条件是这个点的所有前驱都被排序,而且这个点没被排序。然后转移就好了,最终状态就是所有点都完成排序。

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cmath>
 6 #include <algorithm>
 7 #include <string>
 8 #include <queue>
 9 #include <stack>
10 #include <vector>
11 #include <map>
12 #include <set>
13 #include <functional>
14 #include <time.h>
15
16 using namespace std;
17
18 const int INF = 1<<30;
19 const int MAXN = 16;
20
21 int dp[1<<MAXN];
22 int pre[MAXN]; //记录每个点的前驱集合
23 char name[MAXN][MAXN]; //记录每个人物的名字
24 char str[2][MAXN];
25 int n, m;
26
27 void input() {
28     //读数据及其之间的关系。
29     //并且把他们存起来,给每一个名字一个编号
30     //处理出来每个点的前驱存在pre[]中
31     int u, v;
32     n = 0;
33     memset(pre, 0, sizeof(pre));
34     for (int i = 0; i < m; i++) {
35         scanf("%s%s", str[0], str[1]);
36
37         for (u = 0; u < n; u++) //找到这个字符串
38             if (strcmp(name[u], str[0])==0)
39                 break;
40         if (u==n) strcpy(name[n++], str[0]); //如果没找到,插入这个字符串
41
42         for (v = 0; v < n; v++)
43             if (strcmp(name[v], str[1])==0)
44                 break;
45         if (v==n) strcpy(name[n++], str[1]);
46
47         pre[v] |= (1<<u); //u是v的前驱,所以,把u加进v的前驱集合
48     }
49 //for (int i = 0; i < n; i++) printf("%d ", pre[i]); puts(""); //输出前驱集合
50 }
51
52 void solve() {
53     //动态规划
54     //枚举每个状态(已经有拓扑序的集合),然后枚举假如这个集合的点
55     memset(dp, 0, sizeof(dp));
56     dp[0] = 1; //初始状态
57
58     for (int S = 0; S < (1<<n); S++) if (dp[S]!=0) { //剪枝
59         for (int i = 0; i < n; i++) if (((S&pre[i])==pre[i]) && !(S&(1<<i))) { //i的前驱全部在此状态中,并且i不在
60             dp[S|(1<<i)] += dp[S];
61         }
62     }
63
64     printf("%d\n", dp[(1<<n)-1]); //最终状态时所有点都被排序
65 }
66
67 int main() {
68     #ifdef Phantom01
69         freopen("ZJU1346.txt", "r", stdin);
70     #endif //Phantom01
71
72     while (scanf("%d", &m)!=EOF) {
73         input();
74         solve();
75     }
76
77     return 0;
78 }

ZJU 1346

ZJU 1346 Comparing Your Heroes 状态压缩DP 拓扑排序的计数

时间: 2024-07-30 13:26:30

ZJU 1346 Comparing Your Heroes 状态压缩DP 拓扑排序的计数的相关文章

ZOJ3471 状态压缩DP

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3471 Recently, researchers on Mars have discovered N powerful atoms. All of them are different. These atoms have some properties. When two of these atoms collide, one of them disappears and

POJ 3254 Corn Fields 状态压缩DP (C++/Java)

http://poj.org/problem?id=3254 题目大意: 一个农民有n行m列的地方,每个格子用1代表可以种草地,而0不可以.放牛只能在有草地的,但是相邻的草地不能同时放牛, 问总共有多少种方法. 思路: 状态压缩的DP. 可以用二进制数字来表示放牧情况并判断该状态是否满足条件. 这题的限制条件有两个: 1.草地限制. 2.相邻限制. 对于草地限制,因为输入的时候1是可以种草地的. 以"11110"草地分析,就只有最后一个是不可以种草的.取反后得00001  .(为啥取反

HDU1565(状态压缩dp)

方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8170    Accepted Submission(s): 3095 Problem Description 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数

HDU 3001【状态压缩DP】

题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数据的预处理,利用数组分解各个位数,从而达到类似二进制的目的. 然后就是状态的表示,dp[s][i]表示状态s时到达i的最优值. 状态转移也一目了然,不废话. #include<stdio.h> #include<string.h> #include<algorithm> u

Victor and World(spfa+状态压缩dp)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5418 Victor and World Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 262144/131072 K (Java/Others)Total Submission(s): 958    Accepted Submission(s): 431 Problem Description After trying hard fo

poj 3311 Hie with the Pie(状态压缩dp)

Description The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible. Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait for 1 or more (up to 10) orders to be

HDU--1074(状态压缩DP)

典型的状态压缩DP,给出了每件作业的截止时间和花费,求让老师扣分最少的写作业方式.把完成n种作业用状态2^n-1表示,dp[s]表示 完成状态s时,最小扣分.比如“111”,那么可以由“011”,“110”,“101”转移过来,分别表示选了0,1号作业,1,2号作业,0,2号作业. t[s]表示状态S记录的总时间.dp[s] = min{dp[j]+c[k] - d[k]},其中j = i^(1<<k),0<k<n;pre[s]表示状态s完成时,最末尾完成的作业, #include

poj 3254 Corn Fields(状态压缩dp)

Description Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ M ≤ 12; 1 ≤ N ≤ 12) square parcels. He wants to grow some yummy corn for the cows on a number of squares. Regrettably, some of the squares are infertile and

poj 2411 Mondriaan&#39;s Dream(状态压缩+dp)

 题意:用1*2砖块铺满n*m的房间. 思路转自:http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html 因为这道题输入范围在11*11之间,所以可以先打表直接输出.......... 状态压缩DP 经典覆盖问题,输入n和m表示一个n*m的矩形,用1*2的方块进行覆盖,不能重叠,不能越出矩形边界,问完全覆盖完整个矩形有多少种不同的方案 其中n和m均为奇数的话,矩形面积就是奇数,可知是不可能完全覆盖的.接着我们来看