一道杨氏矩阵题目 201806

本文介绍了杨氏矩阵及其在组合表示理论中的应用。给出了完成杨氏矩阵基本操作(创建、查找、增加、删除)的题目描述,包括输入输出格式、数据范围和样例。解决方案中,查找采用Step-wise线性搜索,增添和删除通过比较与交换元素实现,同时提到了一些实现时需要注意的细节和陷阱。
摘要由CSDN通过智能技术生成

介绍

杨氏矩阵(Young Tableau)是对组合表示理论和舒伯特演算很有用的工具,它提供了一种方便的方式来描述对称和一般线性群的群表示,并研究它们的性质。本次任务中我们将对杨氏矩阵的基本操作进行一些探索。

杨氏矩阵一般指一个m×n 的二维数组,它的每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。需要注意的是,在这个矩阵中允许一些元素不存在的情况发生,也可以认为这些元素被设置成为无穷大(∞)。
在这里插入图片描述

对于一组特定数据,杨氏矩阵的形式并不唯一。

题目

完成杨氏矩阵的创建、查找、增加、删除操作。

输入格式

输入一共有五行

第一行包含四个正整数,分别为N N1 N2 N3

第二行包含N个整数,储存了杨氏矩阵的内容,矩阵元素均为大于零不重复的正整数,-1代表矩阵内部换行,且该行最后一个数为-1,注意N并不等于矩阵元素的个数

第三行包含N1个正整数,需要同学们查找这些元素在杨氏矩阵中的位置

第四行包含N2个正整数,每一个代表需要插入到当前杨氏矩阵中的元素,不会给出重复的元素。

第五行包含N3个正整数,每一个代表需要删除的元素,不会给出当前矩阵中不存在的元素。

输入样例

11 2 2 2
2 5 6 -1 4 10 -1 7 -1 15 -1
5 13
8 12
10 7

根据输入样例建立的杨氏矩阵如下
在这里插入图片描述
查找其中的5,13。找到5位于(0,1),而13不存在
在这里插入图片描述
插入8,12到矩阵中。完成后,可以得到(此处结果不唯一)
在这里插入图片描述

删除矩阵中的10,7。完成后,可以得到(此处结果不唯一)

在这里插入图片描述

输入数据范围:

矩阵中元素的值的值位于区间[1,2147483647]内。
0<N<1000000,0<N1<N , 0<N2<50000 , 0<N3<50000

输出格式

输出包含三行。

第一行给出查找结果:依次给出各个元素的坐标,如果元素不存在则认为坐标是(-1,-1)

第二行给出插入操作完成后的杨氏矩阵:分别输出每一行的所有元素值,输出-1代表换行,最后一个输出必须是-1。结果不唯一,你需要保证:1、结果是一个杨氏矩阵。2、矩阵中包含当前存在的所有元素

第三行给出删除操作完成后的杨氏矩阵:分别输出每一行的所有元素值,输出-1代表换行,最后一个输出必须是-1。结果不唯一,你需要保证:1、结果是一个杨氏矩阵。2、矩阵中包含剩余的所有元素

输出样例

0 1 -1 -1
2 5 6 8 -1 4 10 12 -1 7 -1 15 -1
2 5 6 8 -1 4 12 -1 15 -1

限制

时间: 4000 ms 内存: 20000 KB

思路

本题目中实现杨氏矩阵的增删、查找功能,可以考虑用二维数组结构存储数据。第一行永远是最长的,因此每添加一行只需重新申请同样大一块内存。

查找

使用Step-wise线性搜索解法,从左下或者右上开始查找。以右上为例,如果该数字比要查找的数字大,则说明该位置下方所有元素都大、向左移1位;否则同理向下移1位,复杂度O(n),在本题目中已经足够。其余的四分分解算法、二分查找也可以考虑,不做赘述。

增添

显然这里需要一对数字记录目标数字实时位置。
先把要添加的元素加到左下角,然后比较其左上两个位置的数字,如果比大的那个小则与其交换,重复直到比二者都大(也就是没法交换,位置正确)为止。
因为题目给的数据是int范围的一半,不妨考虑使用unsigned int,这样0xffffffff即int的-1表示unsigned int的最大值、也表示行结束,方便输出时的判断。
特殊情况有:
1.矩阵刚好填满,这样左下角已经有了数字而不是0xffffffff,需要先行判断,并且添加一行。显然这样构造的杨氏矩阵每行大小有上界,列数不定,所以列指针数组要足够大。
2.交换时发现到了最上面或最左边,这样只要考虑一个方向即可。

删除

先用查找算法找到位置,然后假定这个位置为空,看其下方和右方的数字,与其中小的交换(具体实现只要赋值就可以了,因为原位置是空嘛),最后这个空位右下全都是空位为止。
特殊情况为刚好移到最右边或者最下方,前者比较好办,后者则有可能刚好删除之后这一行刚好空了,如果有变量记录行数则要-1。

某几个坑

1.因为OJ平台的原因,每行末尾不能有空格,否则会判错(这个也真是……)
2.有的算法用qsort会Bad Syscall,用std::sort就没事。

示例

//这里用了lambda表达式,请使用支持C++11的编译器测试
//请勿全盘照搬!!!
#include<stdio.h>
#include<string.h>
//#pragma warning(disable:4996)

#define nulluint (unsigned int)(-1)

typedef  unsigned int uint;
inline void swap(uint&a,uint&b){uint c=a;a=b;b=c;}
int main(){
	uint n,findn,addn,deln;
	uint firstl[1024],
		**head,//yang mat
		firstn=0,//max x size, last is -1, so data 0~firstn-2
		maxl,// max abled y size
		nowl,//now pointer y
		nowb,//now pointer x
		hasl=0;//now has lines, 0~hasl-1

	uint tmp;
	/*find with arg:
	head,hasl,firstn,tmp
	return nowl,nowb
	*/
	auto find=[&](){
		nowl=0;
		nowb=firstn-2;
		do{
			if(head[nowl][nowb]>tmp)nowb--;//left larger,turn left
			else if(head[nowl][nowb]<tmp)nowl++;//else turn down
			else return;
		}while(nowl<hasl && nowb<firstn);
		nowl=nulluint;
		nowb=nulluint;
		return;
	};
	/*output with arg:
	head,hasl,firstn
	*/
	auto printmat=[&](){
		for(nowl=0;nowl<hasl-1;nowl++){
			nowb=0;
			while(head[nowl][nowb]!=nulluint){
				printf("%d ",head[nowl][nowb]);
				nowb++;
			}
			printf("-1 ");
		}
		nowb=0;
		while(head[nowl][nowb]!=nulluint){
			printf("%d ",head[nowl][nowb]);
			nowb++;
		}
		printf("-1");
	};
	/*insert with arg:
	head,hasl,firstn,tmp
	*/
	auto addp=[&](){
		nowl=hasl-1;
		nowb=firstn-2;
		if(head[nowl][nowb]!=nulluint){
			head[hasl]=new uint[firstn];
			memset(head[hasl],nulluint,sizeof(uint)*firstn);

			hasl++;
			nowl++;
			nowb=0;
			head[nowl][nowb]=tmp;
			while(nowl!=0 && head[nowl-1][nowb]>head[nowl][nowb]){
				swap(head[nowl-1][nowb],head[nowl][nowb]);
				nowl--;
			}
			return;
		}

		head[nowl][nowb]=tmp;
		while(nowl!=0 && nowb!=0){
			if(head[nowl-1][nowb]>head[nowl][nowb-1]){
				if(head[nowl-1][nowb]>tmp){
					swap(head[nowl][nowb],head[nowl-1][nowb]);
					nowl--;
				}
				else return;
			}
			else{
				if(head[nowl][nowb-1]>tmp){
					swap(head[nowl][nowb],head[nowl][nowb-1]);
					nowb--;
				}
				else return;
			}
		};
		if(nowl==0){
			while(nowb!=0 && head[nowl][nowb-1]>head[nowl][nowb]){
				swap(head[nowl][nowb-1],head[nowl][nowb]);
				nowb--;
			}
		}
		else if(nowb==0){
			while(nowl!=0 && head[nowl-1][nowb]>head[nowl][nowb]){
				swap(head[nowl-1][nowb],head[nowl][nowb]);
				nowl--;
			}
		}

	};

	/*delete some items
	first find the item,then change it to nulluint
	*/
	auto delp=[&](){
		find();
		if(nowl!=nulluint && nowb!=nulluint){
			//head[nowl][nowb]=nulluint;
			while(nowl!=hasl-1 && nowb!=firstn-2){
				if(head[nowl+1][nowb]>head[nowl][nowb+1]){
					head[nowl][nowb]=head[nowl][nowb+1];
					nowb++;
				}
				else if(head[nowl+1][nowb]<head[nowl][nowb+1]){
					head[nowl][nowb]=head[nowl+1][nowb];
					nowl++;
				}
				else{
					head[nowl][nowb]=nulluint;
					break;
				}
			}
			if(nowl==hasl-1){
				if(nowb==0 && head[nowl][nowb+1]==nulluint){//last line is empty
					head[nowl][nowb]=nulluint;
					hasl--;
				}
				else{//not empty
					while(head[nowl][nowb+1]!=nulluint){
						head[nowl][nowb]=head[nowl][nowb+1];
						nowb++;
					}
					head[nowl][nowb]=nulluint;
				}
			}
			else if(nowb==firstn-2){
				while(head[nowl+1][nowb]!=nulluint){
					head[nowl][nowb]=head[nowl+1][nowb];
					nowl++;
				}
				head[nowl][nowb]=nulluint;

			}

		}
	};
	
	scanf("%u%u%u%u",&n,&findn,&addn,&deln);
	memset(firstl,nulluint,sizeof(uint)*1024);
	do{
		scanf("%u",firstl+firstn);
	}while(firstl[firstn++]!=nulluint);//x:0~firstl-2 ; firstl-1 is -1; firstl is line size
	maxl=1000*1000/firstn;
	head=new uint*[maxl];
	head[0]=firstl;
	nowb=firstn-1;
	for(uint i=firstn;i<n;i++){
		if(head[hasl][nowb]==nulluint){
			nowb=0;
			hasl++;
			head[hasl]=new uint[firstn];
			memset(head[hasl],nulluint,sizeof(uint)*firstn);
		}
		else{
			nowb++;
		}
		scanf("%u",head[hasl]+(nowb));
	}
	hasl++;//0~hasl-1

	
	for(uint i=0;i<findn-1;i++){
		scanf("%u",&tmp);
		find();
		printf("%d %d ",nowl,nowb);
	}
	scanf("%u",&tmp);
	find();
	printf("%d %d\n",nowl,nowb);

	///
	for(uint i=0;i<addn;i++){
		scanf("%u",&tmp);
		addp();
	}
	printmat();
	putchar('\n');
	//
	for(uint i=0;i<deln;i++){
		scanf("%u",&tmp);
		delp();
	}
	printmat();
	//getchar();getchar();
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值