蓝桥杯:3000米排名预测(带限制的全排列)递归解法(DFS+状态重置)
问题描述
3000米长跑时,围观党们兴高采烈地预测着最后的排名。因为他们来自不同的班,对所有运动员不一定都了解,于是他们分别对自己了解的一些运动员的实力作出了评估,即对部分运动员做了相对排名的预测,并且告诉了可怜留守的班长。因为无聊,于是他们就组团去打Dota去了。比赛结束后他们向班长询问最后的排名,但班长不记得了,只记得他们中哪些人的预测是正确的,哪些人的预测是错误的。他们想知道比赛的排名可能是什么。
输入格式
第一行两个整数n, m,n为运动员数量,m为围观党数量。运动员编号从0到n-1。
接下来m行,每行为一个围观党的相对排名预测。每行第一个数c表示他预测的人数,后面跟着c个0~n-1的不同的数,表示他预测的运动员相对排名,最后还有一个数,0表示这个预测是错误的,1表示是正确的。
输出格式
第一行一个数k为有多少种排名的可能。
下面k行,每行一个0~n-1的排列,为某一个可能的排名,相邻的数间用空格隔开。所有排名按字典序依次输出。
样例输入
Input Sample 1:
3 2
2 0 1 1
2 1 2 0
Input Sample 2:
3 2
2 0 1 1
2 2 1 0
样例输出
Output Sample 1:
2
0 2 1
2 0 1
Output Sample 2:
1
0 1 2
数据规模和约定
1<=n<=10, 2<=c<=n, 1<=m<=10,保证数据合法,且答案中排名可能数不超过20000。对于一个排名序列,一个预测是正确的,当且仅当预测的排名的相对顺序是排名序列的一个子序列。一个预测是错误的,当且仅当这个预测不正确。
思路
对于全排列,这题判断全排列串合法否的方式比较繁琐,但是最终用时还是比较少的(上限1s)
这题限制条件比较多,一个一个来:
- 将一个长度为n的预测序列分为 n-1 个 “排名对”
- 即 1 2 3 4 可以分为 3 个排名对:<1,2> <2, 3> < 3, 4>
- 搜索 “排名对” 中两个元素在当前全排列串中的下标位置 index1, index2
- 如果 index1 > index2 则说明存在矛盾的排名
- 如果 index1 <= index2 且两个元素都在都在当前全排列串中则说明该“排名对” 是合法的,即命中
- 对于所有真假设,要求 所有单个假设的所有 “排名对” 不存在矛盾
- 对于所有假假设,要求 不能有单个假设的所有 “排名对” 全部命中当前的全排列串
例子
AC完整代码
#include <iostream>
using namespace std;
#define maxlen 13
int n, m;
int ans[maxlen]; // 答案
int visited[maxlen]; // 访问控制数组
// 约束条件
// limit[i] 存储第 i 个预测的排名序列
// limit[i][0] 是第i个预测序列的长度
// limit[i]的最后一个数字 limit[i][limit[i][0]+1] 是该预测的真假
int limit[maxlen][maxlen];
// 结果
int cnt = 0;
int result[20001][maxlen];
// 在ans的前len+1个元素中找x的下标,未找到,返回大值,在后序判断中表示合法
int find(int x, int len)
{
for(int i=0; i<=len; i++)
<