介绍
杨氏矩阵(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;
}