题解:2018级算法第一次练习赛 妙妙趣排序

问题描述:

样例:

实现解释:

针对这个问题,首先可以想到有两种解决方法:构造全排列然后分别筛选后进行判断,逆序判断。

而显然对于前者时间是一定不够的(10以上数字的全排列构建时间就已经很长了),所以需要进行逆序判断。

即如果是符合条件的数组,那么经过筛选器后一定会是一个即将排好序的数组。所以只需要对所有即将排好序的数组倒序通过筛选器,得到筛选前的数组再判断即可。

注意筛选器的处理有两种可能:不必更换和更换两个位置的值,所以在判断之前的筛选器时需要分别对更换前后进行判断。

而对于即将排好序的数组的构建,可以使用巧妙方法:先1-n分别放在对角线处,然后将剩下的值按顺序放入空白的地方,就一定是一个即将排好序的数组(注意进行重复数组的去除)。

这里也是只语言描述不够清晰,还是参考代码进行最好。

完整代码:

#include<iostream>
using namespace std;

int num[100000][51];
int filter[11][2];
long long ans = 0;

void dfs(int t,int a[]){
	int temp;

	if (t == 0) {//经过了所有筛选器筛选,所以++
		ans++;
		return ;
	}

	int l = filter[t][0];
	int r = filter[t][1];

	if (a[l] > a[r])//不可能是经过这个筛选器得到的数列,所以直接返回
	{
		return ;
	}
	else
	{
		//判断前一个筛选器
		dfs(t-1,a);

		//交换后再进行判断
		temp = a[l];
		a[l] = a[r];
		a[r] = temp;
		dfs(t-1,a);

		//交换回来防止出错
		temp = a[r];
		a[r] = a[l];
		a[l] = temp;
	}

}
int main()
{
	int cnt,fcnt;
	int n,N;
	int i,j;
	cin >> cnt;
	while(cnt--)
	{
		ans = 0;
		cin >> n >> fcnt;
		N = n*n;

		for (i=1;i<=fcnt;i++)
		{
			cin >> filter[i][0] >> filter[i][1];
		}

		//准备构建即将排好序的数列,把1-n分别放到对角线
		for (i=1;i<=n;i++)
		{
			for (j=1;j<=n;j++)
			{
				num[(i-1)*n+j][j] = i;//(i-1)*n+j就是自动随着j向下移动
			}
		}

		//补充空白的位置,按顺序把剩下的填进去
		for (i=1;i<=n;i++)
		{
			for (j=1;j<=n;j++)
			{
				for (int k=1,temp=1;k<=n;k++)
				{
					if (temp==i) temp++;//是填入的值所以跳过 

					if (k==j) continue;//已经有之前填入的对角线了

					num[(i-1)*n+j][k] = temp++;
				}
			}
		}

		//将重复的数列进行屏蔽处理
		for (i=1;i<=N;i++){
			for (j=i+1;j<=N;j++){
				//遍历判断是否相同
				int k = 1;
				for(;num[j][k]==num[i][k]&&k<=n;k++){}
				if(k==n+1) num[j][1] = -1;
			}
		}

		//分别对即将排好序的数列进行反向筛选
		for (i=1;i<=N;i++){
			if (num[i][1] == -1) continue;
			dfs(fcnt,num[i]);
		}

		cout << ans << endl;
	}

	return 0;
}

  

原文地址:https://www.cnblogs.com/doUlikewyx/p/11701188.html

时间: 2024-10-09 18:40:12

题解:2018级算法第一次练习赛 妙妙趣排序的相关文章

题解:2018级算法第一次练习赛 等比数列求和

问题描述: 样例: 实现解释: 这里等比数列求和使用到的知识点包括:分治和快速幂 其中分治的方法和快速幂的方法是从博客中学习到的: 等比数列分治求和:https://blog.csdn.net/qq_35937273/article/details/82750298 快速幂方法:https://www.cnblogs.com/lca1826/p/6748372.html 结合到本题目中可参考完整代码. 在分治求和和快速幂之外取模操作的实现解释如下: 根据描述可知最后的值是很大的,所以需要取余,但

题解:2018级算法第二次上机 Zexal的流水线问题

题目描述: 样例: 实现解释: 最基础的流水线调度问题,甚至没有开始和结束的值 知识点:动态规划,流水线调度 实现方法即得出状态转移方程后完善即可,设a[][i]存储着第一二条线上各家的时间花费,t[][i]存储着i处进行线路切换的花费,f[][i]存储着各线在i处的最小花费. 则对每一个f[][i]应有如下的转移方程: f[0][1] = a[0][1]; f[1][1] = a[1][1]; f[0][i] = min(f[0][i-1]+a[0][i],f[1][i-1]+t[1][i-1

A1-2017级算法第一次上机练习赛 C AlvinZH去图书馆

题目描述 AlvinZH最近在看<冰与火之歌>系列,这天,他又看完了一本书,于是决定去图书馆再借一本.大家知道,在去图书馆的路上,有一条"扯蛋路".大概是这个样子的(秀一波拍照技术): AlvinZH从第一块石砖出发,接下来他可以走到第二块石砖或第三块石砖,有时候走的很不爽,甚至可以直接跨过两个石砖,到达第四块石砖,但是不能连续两次这种操作,因为这样...对身体不好.现在假设有一条含n块石砖的小路,请你计算出AlvinZH从第一块石砖出发有多少种安全的走法. 输入 输入将由

题解:2018级算法第二次上机 Zexal的钢管切割

题目描述: 样例: 实现解释: 经典钢管切割问题的变形:最赔钱切割 知识点:动态规划,钢管切割 实现方法即得出状态转移方程后完善为代码即可,先设数组price[i]存储着i长度钢管切割后的最小值,p[i]存储着i长度钢管不切割的值,price数组既是本问题的dp数组. 经过分析可知状态转移方程为: price[0] = 0; price[i] = min(p[1]+price[i-1],p[2]+price[i-2],...p[i-1]+price[1],p[i]); 因为price[i]已经是

题解:2018级算法第二次上机 Zexal的排座位

题目描述: 样例: 实现解释: 一道看似复杂但实际既是斐波那契变形的题目 知识点:递推,斐波那契 通过问题的描述,可以得到以下规律:(除了座位数为一时)男生坐最后时,倒数第二个一定是女生:女生坐最后,倒数第二个均可.转化:i个位置时男生结尾的情况数等于i-1个位置时女生结尾的情况数,i个位置时女生结尾的情况数等于i-1个位置时的总情况数. 于是便可得出两种解决方案:斐波那契变形和直接循环递推 斐波那契变形: i位置男生结尾的情况 = i-1位置女生结尾情况数 = i-2位置总情况数 i位置女生结

题解:2018级算法第二次上机 Zexal的竞赛

题目描述: 样例: 实现解释: 一道需要一点思考的动态规划题目 知识点:动态规划,数据记录 首先将题目描述调整:分别输入不同分数的题目总分(便于后续计算),当获得了i分数的总分后无法获得i-1和i+1的总分. 于是便可先利用score[i]储存i分数的总分数,用dp[i]储存以前i个分数为范围进行题目选择时的最大可获得分数.dp便是动态规划所用的数组. 于是可得状态转移方程如下: dp[0] = score[0]; dp[1] = score[1]; dp[i] = max(dp[i-2]+sc

题解:2018级算法第三次上机 C3-Zexal的浩瀚星辰

题目描述: 样例: 实现解释: 一道结合了火箭发射的贪心题目 知识点: 贪心,优先队列 题目分析: 根据题目描述可知,延迟后时间是正常推进的,也就是假设共有n个火箭,推迟k小时.则在到达k+1小时时,每过一个小时只要火箭没发射完都会有k(如果k大于n就是有剩余数量)个火箭会遭受延迟的损失,显然这是必然的(因为到达k小时前的损失都已经确定了,无法改变). 那么依据题意只要使得每次这k个火箭的损失最小即可,而如何最小:让其中单位时间损失最大的火箭发射即可,这样一定比发射其他火箭的损失要小. 于是便可

题解:2018级算法第四次上机 C4-商人卖鱼

题目描述: 样例: 实现解释: 需要简单分析的贪心题 知识点: 贪心,自定义排序,提前存储 题目分析: 卖鱼,鱼卖出去需要时间,鱼没被卖出去之前需要吃饲料 则有,如果卖a鱼的话b鱼会吃饲料c份,而卖b鱼a鱼会吃d份,为了消耗更少的饲料,如果c比d小,则应该卖a鱼.而计算上即c = a.t*b.d,d = a.d*b.t. 因此需要做的就是依据上述公式对所有鱼的买卖优先级进行排序(排序的cmp函数实现有进行简单解释),然后按顺序计算需要的饲料数即可. 为了不再遍历计算卖鱼时的花费,这里用total

题解:2018级算法第四次上机 C4-最小乘法

题目描述: 样例: 实现解释: 和字符串处理结合的动态规划,个人认为比较难分析出状态转移方程,虽然懂了之后挺好理解的 知识点: 动态规划,字符串转数字 题目分析: 首先按照最基础:依据题意设计原始dp数组,这里根据描可知有三个数需要考虑:数字串开始,数字串结尾和之间插入的乘号数量,因此基础dp[i][j][k],分别为开始,结束脚标和乘号数. 然后推导:考虑到添加乘号,为了使状态转移方程简单,最后固定位置,因此可以考虑每次都在最后插入乘号,插入乘号的位置便可倒序确定.此时数字串的开始位置便可固定