HDU 4917 Permutation 拓扑排序的计数
题意:
一个有n个数的排列,给你一些位置上数字的大小关系。求合法的排列有多少种。
思路:
数字的大小关系可以看做是一条有向边,这样以每个位置当点,就可以把整个排列当做一张有向图。而且题目保证有解,所以只一张有向无环图。这样子,我们就可以把排列计数的问题转化为一个图的拓扑排序计数问题。
拓扑排序的做法可以参见ZJU1346 。
因为题目中点的数量比较多,所以无法直接用状压DP。 但是题目中的边数较少,所以不是联通的,而一个连通块的点不超过21个,而且不同连通块之间可以看做相互独立的。所以我们可以对于每个连通块分别求解,然后利用排列组合的知识,把他们组合起来。这样就可以得到最终解了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <string>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <time.h> using namespace std; typedef __int64 ll; const int INF = <<;
const int MAXM = ;
const int MAXN = ;
const ll MOD = (ll) 1e9+; ll dp[<<MAXM]; //
ll combine[MAXN][MAXN]; //组合数
int Matrix[MAXN][MAXN]; //邻接矩阵,1表示正向边,-1表示反向边
int tmp[MAXM], pre[MAXM], num; //求每个连通块的拓扑序用
bool vis[MAXN]; //求连通块用
int n, m, tot;
ll ans; void dfs(int u) {
int u2 = num; //当前点的标号
tmp[num++] = u; //把这个点加入集合
vis[u] = true; int v;
for (int i = ; i <= n; i++) if (Matrix[u][i]) { //如果有边
if (!vis[i]) dfs(i); //如果没找过先找后继
if (==Matrix[u][i]) {
for (v = ; v < num; v++) if (tmp[v]==i) {
pre[v] |= (<<u2); //把这个点加入后继的前驱集合
}
}
}
} ll calc() { //计算某个连通块的拓扑数量
memset(dp, , sizeof(dp));
dp[] = ; for (int S = ; S < (<<num); S++) if (dp[S]>)
for (int i = ; i < num; i++) if (((S&pre[i])==pre[i]) && !(S&(<<i))) {
dp[S|(<<i)] = (dp[S|(<<i)]+dp[S])%MOD;
} return dp[(<<num)-];
} void solve() {
memset(vis, false, sizeof(vis));
ans = ;
tot = n;
for (int i = ; i <= n; i++) if (!vis[i]) { //搜连通块
memset(pre, , sizeof(pre)); num = ;
dfs(i);
if (num<) //只有一个或者两个点的情况,拓扑序时确定的
ans = (((num*combine[tot][num])%MOD)*ans)%MOD;
else
ans = (((calc()*combine[tot][num])%MOD)*ans)%MOD; tot -= num;
} printf("%I64d\n", ans);
} int main() {
#ifdef Phantom01
freopen("HDU4917.in", "r", stdin);
// freopen("HDU4917.out", "w", stdout);
#endif //Phantom01 for (int i = ; i < MAXN; i++) { //预处理组合数(杨辉三角)
combine[i][] = ;
for (int j = ; j <= i; j++)
combine[i][j] = (combine[i-][j-] + combine[i-][j])%MOD;
} while (scanf("%d%d", &n, &m)!=EOF) {
memset(Matrix, , sizeof(Matrix));
int u, v;
for (int i = ; i < m; i++) {
scanf("%d%d", &u, &v);
Matrix[u][v] = ;
Matrix[v][u] = -;
}
solve();
} return ;
}
HDU4917
写的时候,莫名其妙的wa了一发,要数据来对拍才发现是中间结果溢出了……所以,小心的调整运算顺序和适当的加括号很有必要。
HDU 4917 Permutation 拓扑排序的计数的更多相关文章
- HDU.2647 Reward(拓扑排序 TopSort)
HDU.2647 Reward(拓扑排序 TopSort) 题意分析 裸的拓扑排序 详解请移步 算法学习 拓扑排序(TopSort) 这道题有一点变化是要求计算最后的金钱数.最少金钱值是888,最少的 ...
- ACM: hdu 2647 Reward -拓扑排序
hdu 2647 Reward Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Des ...
- HDU 2647 Reward (拓扑排序)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2647 题意是给你n点m条有向边,叶子点(出度为0)上的值为888,父亲点为888+1,依次计算... ...
- hdu 5438 Ponds 拓扑排序
Ponds Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/contests/contest_showproblem ...
- CF798E. Mike and code of a permutation [拓扑排序 线段树]
CF798E. Mike and code of a permutation 题意: 排列p,编码了一个序列a.对于每个i,找到第一个\(p_j > p_i\)并且未被标记的j,标记这个j并\( ...
- 【NOIP2017】逛公园(最短路图,拓扑排序,计数DP)
题意: 策策同学特别喜欢逛公园. 公园可以看成一张 N 个点 M 条边构成的有向图,且没有自环和重边.其中 1 号点是公园的入口, N 号点是公园的出口,每条边有一个非负权值,代表策策经过这条边所要花 ...
- hdu 4857 逃生 拓扑排序+PQ,剥层分析
pid=4857">hdu4857 逃生 题目是求拓扑排序,但不是依照字典序最小输出,而是要使较小的数排在最前面. 一開始的错误思路:给每一个点确定一个优先级(该点所能到达的最小的点) ...
- HDU 4917 Permutation
意甲冠军: 序列p1.p2.p3--pn由1.2.3--n这些数字 现在给出一些条件pi<pj 部条件的排列的个数 思路: 非常easy想到用一条有向的线连接全部的pi和pj 那么就构成了 ...
- HDU 1285 经典拓扑排序入门题
确定比赛名次 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
随机推荐
- LeetCode 744. Find Smallest Letter Greater Than Target (时间复杂度O(n))
题目 太简单了,直接上代码: class Solution { public: char nextGreatestLetter(vector<char>& letters, cha ...
- 51nod 1307 绳子与重物 (标记父节点更新即可)
1307 绳子与重物 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 有N条绳子编号 0 至 N - 1,每条绳子后面栓了一个重物重量为Wi,绳子的最大负重为Ci. ...
- swift语言点评十八-异常与错误
1.错误类型与枚举的结合 enum VendingMachineError: Error { case invalidSelection case insufficientFunds(coinsNee ...
- checkbox控制显示隐藏
显示文本框<input type = "checkbox" id="checkbox" onclick="on_hide();"/&g ...
- Linux下重启mysql数据库的方法
原文地址:Linux下重启mysql数据库的方法作者:于士博的视频教程 方法一: 命令: [root@localhost /]# /etc/init.d/mysql start|stop|rest ...
- UVA-11584 Partitioning by Palindromes 动态规划 回文串的最少个数
题目链接:https://cn.vjudge.net/problem/UVA-11584 题意 给一个字符串序列,问回文串的最少个数. 例:aaadbccb 分为aaa, d, bccb三份 n< ...
- 紫书 习题 8-16 UVa 1618 (中途相遇法)
暴力n的四次方, 然而可以用中途相遇法的思想, 分左边两个数和右边两个数来判断, 最后合起来判断. 一边是n平方logn, 合起来是n平方logn(枚举n平方, 二分logn) (1)两种比较方式是相 ...
- Java多线程-基础知识
一. 进程是执行中的程序,程序是静态的(我们写完以后不运行就一直放在那里),进程是执行中的程序,是动态概念的.一个进程可以有多个线程. 二. 多线程包含两个或两个以上并发运行的部分,把程序中每个这样并 ...
- Mysql导入Sql文件时报Error Code: 2013 - Lost connection to MySQL server during query
MySql 有时我们导入sql文件,文件过大,导致Error Code: 2013 - Lost connection to MySQL server during query这种错误 执行以下: S ...
- 【转】Geometry cannot have Z values
http://blog.csdn.net/tweeenty/article/details/44246407 在对矢量要素类添加要素,进行赋几何信息时(FeatureBuffer.Shape = IG ...