2019.8.15 360笔试编程题 求表面积 序列重组(C/C++)

1.求表面积

题目描述:

将长N*M厘米的矩形区域划分成N行M列(每行每列的宽度均为1厘米),在第i行第j列的位置上叠放Ai,j个边长为1厘米的正方体(1≤Ai,j≤100),所有正方体就组成了一个立体图形,每个正方体六个面中的一部分会被其它正方体遮挡,未被遮挡的部分的总面积即为该立体图形的表面积,那么该立体图形的表面积是多少平方厘米?

输入:

第一行包含两个整数N和M,1≤N,M≤1000。
接下来N行,每行包含M个整数,第i行的第j个整数表示Ai,j。

输出:

输出表面积的大小。

样例:

输入:
	2 2
	2 1
	1 1
输出:
	20

思路:

把这个模型分成3个方向去看,前左上。其中从上看和从下看是一样的,也就是有方块的地方,顶和底就都+1。左前是有镂空的,用爬山下山的方式来数有多少个面:首先在这个输入矩阵的外围包上一圈0,如从前面看,就从前面的0开始往方块上走,比如样例第一列就是0 1 2 0,当平面抬高了,可认为出现了表面,就用后面的高度-前面的高度取绝对值,累加即可。

代码:

莫得代码

考试当天做出来了,AC


2.序列重组

两个数字,m进制,n位数,可以重新排序数字的顺序,两个数对应相加并对m取模而不进位,求最大和

题目描述:

在一个古老的国度,这个国家的人并不懂得进位,但是对取模情有独钟,因此诞生了一个经典的问题,给出两个在m进制下含有n位的数字,你可以分别将这两个数各位上的数字重新排列,然后将两个数按位对应相加并分别对m取模, 这样显然可以得到一个新的m进制下的n位数(可能存在前导0),但是这个结果是不唯一的,问题来了,按照这样的操作,能够得到的最大的m进制下的数字是多少呢。

输入:

输入第一行包含两个正整数n,m分别表示数字含有n位,和在m进制下。(n,m≤100000)
输入第二行和第三行分别包含n个整数,中间用空格隔开,每个整数都在0到m-1之间。每行第i个数表示的是当前数第i位上的数字。

输出:

输出包含n个数字,中间用空格隔开,表示得到的最大的数字,从高位到低位输出,如6在2进制下输出3位的结果是1 1 0。

样例:

输入:
	 5 5
	 4 4 1 1 1
	 4 3 0 1 2
输出:
	 4 4 3 3 2

解释:
	4 4 1 1 1 →1 4 1 4 1
	4 3 0 1 2 →3 0 2 4 1(重排序列不唯一,数位相加后的数字为 4 4 3 8 2,对5取模即可 )

思路:

链表+数组。
也就是尽量去构造加起来更大的数。用两个计数链表来存这两个数字池子里的数,如a[0]代表有a[0]个0,a[1]代表有a[1]个1…,b数组也一样,样例输入就可转换为 a[]={0,3,0,0,2} b[]={1,1,1,1,1}。由于结果上越前的数位上数字越大越好,所以用一个循环i从m-1往0跑,代表当前位上的相加结果,尝试去构造能加起来得到 i 的数字对。因为加起来能得到 i 的数对是固定的,如在样例中m为5,第一次循环时 i=4 ,加起来能得到4的数对只有(0,4)(1,3)(2,2)(3,1)(4,0),所以只要第一个数池里有1,第二个数池里有3,那就能配对,然后必然导致a[1]或者b[3]中小的那个变为0,大的那个变为 abs(a[1]-b[3]) ,计取得 min(a[1],b[3]) 个4,然后a[4]和b[0]也能在此配对,同理又取得 min(a[4],b[0]) 个4。这时候没有配对的了。在循环中当链表中有哪个数没有了,那就删掉那个节点,如a[]={0,3,0,0,2}就转变为a[]={3,2}。
循环往下走的时候,当 i 变到3,每个数的匹配关系从(0,4) (1,3) (2,2) (3,1) (4,0)变为(0,3) (1,2) (2,1) (3,0) (4,4),再次去找匹配对即可。

因为nm都是10万,所以估计上来说,一般就是扫一遍加上一个log,n²是肯定不行的,所以不能直接的去构造数对,要用权值链表来做,不然直接大模拟就好了。这样做看起来是O(M*N)的复杂度,但是由于链表在不停地减小,近似上来说内循环是一个log级别的复杂度,大概能过。

代码:

#include <cstdio>
using namespace std;
const int N = 110000;
struct Node
{
    int Num,key,otherSide,next;
}node[2][N];
int head[2];
bool in[2][N];
int n,MOD;
int res[N];
void deleteNode(int last,int upOrDown)//删除某个节点的下一个节点,如果删头,输入-1
{
    int now = node[upOrDown][ last ].next;
    if(last == -1)
    {
        now = head[upOrDown];
        if(node[upOrDown][ now ].next == -1)
        {
            head[upOrDown] = -1;
            return ;
        }
        head[upOrDown] = node[upOrDown][now].next;
        return;
    }
    node[upOrDown][last].next = node[upOrDown][now].next;
}
void clearList()
{
    for(int i=0;i<=1;i++)
    {
        int now = head[i],last = -1;
        while(now != -1)
        {
            if(node[i][now].Num <= 0)
            {
                in[i][now] = 0;
                deleteNode(last,i);
                now = last==-1?head[i]:node[i][last].next;
            }
            else
            {
                last = now;
                now = node[i][now].next;
            }
        }
    }
}
void list1Push_left()
{
    int now = head[0],last = -1;
    while(now != -1)
    {
        node[0][now].otherSide = node[0][now].otherSide==0 ? MOD-1 : node[0][now].otherSide-1;
        now = node[0][now].next;
    }
    now = head[1],last = -1;
    while(now != -1)
    {
        node[1][now].otherSide = node[1][now].otherSide==0 ? MOD-1 : node[1][now].otherSide-1;
        now = node[1][now].next;
    }
}
void showLinkList()
{
    int temp = head[0];
    printf("*****************输出链表*********************\n");
    while(temp!=-1)
    {
        printf("i=%d Num=%d key=%d 对面=%d next=%d\n",temp,node[0][temp].Num,node[0][temp].key,node[0][temp].otherSide,node[0][temp].next);
        temp = node[0][temp].next;
    }
    for(int i=0;i<MOD;i++)
        if(in[0][i])printf("*");
        else printf("_");
    printf("\n");
    printf("\n");
    temp = head[1];
    while(temp!=-1)
    {
        printf("i=%d Num=%d key=%d 对面=%d next=%d\n",temp,node[1][temp].Num,node[1][temp].key,node[1][temp].otherSide,node[1][temp].next);
        temp = node[1][temp].next;
    }
    for(int i=0;i<MOD;i++)
        if(in[1][i])printf("*");
        else printf("_");
    printf("\n");
    printf("*****************结束*********************\n");
}
int main()
{
//初始化
    scanf("%d%d",&n,&MOD);
    for(int i=0;i<=MOD;i++)
        node[0][i].Num = 0, node[0][i].next = i+1, node[0][i].otherSide = MOD-i-1, node[0][i].key = i;
    node[0][MOD-1].next = -1;//-1代表链表结尾
    head[0] = 0;
    for(int i=MOD;i>=0;i--)
        node[1][i].Num = 0, node[1][i].next = i-1, node[1][i].otherSide = MOD-i-1, node[1][i].key = i;
    node[1][0].next = -1;
    head[1] = MOD-1;
    for(int i=0;i<=MOD;i++)
        res[i] = 0,in[0][i] = 1,in[1][i] = 1;
    int temp;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&temp);
        temp %= MOD;
        node[0][temp].Num ++ ;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&temp);
        temp %= MOD;
        node[1][temp].Num ++ ;
    }

//启动
    for(int m=MOD-1;m>=0;m--)
    {
   //     printf("\n第%d轮,m为%d\n",MOD-m,m);
        clearList();
   //     showLinkList();
        int now = head[0],last;
        while(now!=-1)
        {
            if(in[1][ node[0][now].otherSide ] != 0)
            {
                if(node[0][now].Num > node[1][ node[0][now].otherSide ].Num)
                {
                    int temp = node[0][now].Num - node[1][ node[0][now].otherSide ].Num;
                    res[m] += node[1][ node[0][now].otherSide ].Num;
                    node[0][now].Num = temp;
                    node[1][ node[0][now].otherSide ].Num = 0;
                }
                else
                {
                    int temp = node[1][ node[0][now].otherSide ].Num - node[0][now].Num;
                    res[m] += node[0][now].Num;
                    node[0][now].Num = 0;
                    node[1][ node[0][now].otherSide ].Num = temp;
                }
                if(node[0][now].Num == 0)
                    in[0][now] = 0;
                if(node[1][ node[0][now].otherSide ].Num == 0)
                    in[1][ node[0][now].otherSide ] = 0;
            }
            now = node[0][now].next;
        }
        list1Push_left();
   //     showLinkList();
    }

//输出结果
    int pre0 = 0;//解决前导0判断符
    for(int i=MOD-1;i>=0;i--)
    {
        if(res[i])
        {
            if(i>0)
            {
                for(int j=1;j<=res[i];j++)
                    printf("%d ",i);
                pre0 = 1;
            }
            else if(pre0)
                for(int j=1;j<=res[i];j++)
                    printf("%d ",i);
        }
    }
    printf("\n");
    return 0;
}

贼复杂啊,当天完全没做出来。现在做出来没有OJ,不知道对不对。测得几个数据倒是对了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值