频道栏目
首页 > 资讯 > 其他 > 正文

裁剪表格“编程题”

17-10-23        来源:[db:作者]  
收藏   我要投稿

题目描述:
题目大意:
给一个n*m的矩阵,每个格子都有一个数字v,每次交换两个大小相同的不重叠的子矩阵,输出最后的矩阵。
输入格式:
第一行三个整数n,m,q代表表格的行数和列数和操作次数;
接下来n行,每行m个整数,表示格中的数字。
接下来q行,每行六个数字,r1,c1,r2,c2,h,w,分别表示第一个矩形左上角所在行、所在列,第二个矩形左上角所在行、所在列,这两个矩形的高度和宽度(保证着两个矩形都在原有表格内)。
输出格式:
输出n行,每行m个整数,表示最后的矩阵。
样例输入:

4 4 2
1 1 2 2
1 1 2 2
3 3 4 4
3 3 4 4
1 1 3 3 2 2
3 1 1 3 2 2

样例输出:

4 4 3 3
4 4 3 3
2 2 1 1
2 2 1 1
数据范围:
对于10%的数据,所有的v=1;
对于30%的数据,n,m≤300,q≤300;
对于60%的数据,n,m≤1000,q≤500;
对于100%的数据,2≤n,m≤1000,1≤q≤500;1≤v≤1000000。

题目分析:
先吐槽一下这道题,因为题面中提到高级数据结构,然后有许多人写了splay,出题人为了卡那些人,后面的数据的询问就专门针对splay,结果导致暴力踩标算,直接拿满(暴力就是指直接模拟交换)。后来后面数据改了一下还是有80分,加register还是可以满分。(主要是数据很难兼顾同时卡暴力和splay)。
分析:这道题其实是一道链表题,我们可以记录四个方向(上下左右),每次交换,其实只用修改两个矩形的四周那一圈的连接。于是时间复杂度O(n*q)。
具体操作:先从起点(初始为(1,1),如果(1,1)与其它点交换,则这个点就成为了起点(因为实际上它被换到了(1,1)的位置))出发,分别走到这两个矩形的左上角,然后绕矩形走一圈(在两个矩形上的点是对应着一起走),每次交换两个矩形对应点连出去的指向和外面被连接的点所连回来的指向。这样就相当于交换整个矩形。
还可以优化:只记录两个指向,右、下,因为你输出只根据向右和向下就可以输出,而向右和向下就可以表示4个方向(上面的情况是在双向修改,这里就是单向的)。
链表可以一般写法,也可以指针写。
下附4份代码:1、暴力,2、我写的记录四个方向的链表,3、标算的记录两个方向的链表,4、记录两个方向的链表的指针写法。
附代码:
1、暴力+register:
是我考试代码直接加的register,所以还有特判部分

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int N=1e3+100;
int n,m,q,a[N][N];
bool check;

int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

int main()
{
    freopen("table.in","r",stdin);
    freopen("table.out","w",stdout);

    n=readint();m=readint();q=readint();
    for(register int i=1;i<=n;i++)
        for(register int j=1;j<=m;j++)
        {
            a[i][j]=readint();
            if(a[i][j]!=1) check=true;
        }
    if(check==false)
    {
        for(register int i=1;i<=n;i++)
        {
            for(register int j=1;j<=m;j++)
                cout<

2、记录四个方向的链表: 我之所以把这份代码发在前面,只是因为是我自己写的且耗时很久。因为维护4个方向,写起来复杂,写完后又因为一些情况没考虑,或则手抖写错某个地方,于是调试了很久。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

int n,m,q,pos[2],now1[2],now2[2],r1,c1,r2,c2,h,w,dian1[2],dian2[2];
struct node{
    int w;
    int up[2],down[2],left[2],right[2];//例:up[0]是向上连接的点的横坐标,up[1]纵坐标,其余同理,包括now1,now2,pos,dain1,dian2
}map[1010][1010];


int readint()
{
    char ch;int i=0,f=1;
    for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    if(ch=='-') {ch=getchar();f=-1;}
    for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
    return i*f;
}

int main()
{
    //freopen("table.in","r",stdin);
    //freopen("table.out","w",stdout);

    n=readint();m=readint();q=readint();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            map[i][j].w=readint();
    for(int i=0;i<=n+1;i++)//从0开始到n+1是把原本矩形的一周外面的点也连一次
        for(int j=0;j<=m+1;j++)
        {
             map[i][j].up[0]=i-1;map[i][j].up[1]=j;
             map[i][j].right[0]=i;map[i][j].right[1]=j+1;
             map[i][j].down[0]=i+1;map[i][j].down[1]=j;
             map[i][j].left[0]=i;map[i][j].left[1]=j-1;
        }
    pos[0]=1;pos[1]=1;//赋初始起点
    while(q--)
    {
        r1=readint();c1=readint();r2=readint();c2=readint();h=readint();w=readint();

        memcpy(now1,pos,8);memcpy(now2,pos,8);//这个函数是把第二个位置的赋给第一个位置,8代表赋的长度,以字节计算,一个int4字节
        for(int i=1;i

3、标算的记录两个方向的链表: 简洁,推荐。

#include
using namespace std;
const int N = 1005;
const int MaxN = 1005003;
int n,m,q,num,v[MaxN],f[MaxN][5],lab[N][N];

inline int Readint(){
    register char ch=getchar();
    register int x=0;
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=((x+(x<<2))<<1)+ch-'0',ch=getchar();
    return x;
}

inline int getlab(int a,int b){
    int p=lab[0][0];
    for(register int i=1;i<=a;i++) p=f[p][1];
    for(register int i=1;i<=b;i++) p=f[p][0];
    return p;
}

int main(){
//  freopen("lx.in","r",stdin);
    n=Readint(),m=Readint(),q=Readint();
    for(register int i=1;i<=n;i++)
      for(register int j=1;j<=m;j++)
        v[lab[i][j]=++num]=Readint();
    for(register int i=0;i<=m+1;i++) lab[0][i]=++num,lab[n+1][i]=++num;
    for(register int i=1;i<=n;i++) lab[i][0]=++num,lab[i][m+1]=++num;
    for(register int i=0;i<=n;i++)
      for(register int j=0;j<=m;j++)
        f[lab[i][j]][0]=lab[i][j+1],f[lab[i][j]][1]=lab[i+1][j];
    for(int a,b,c,d,h,w,i=1;i<=q;i++){
        a=Readint(),b=Readint(),c=Readint();
        d=Readint(),h=Readint(),w=Readint();
        register int p1=getlab(a-1,b-1),p2=getlab(c-1,d-1);
        register int t1,t2,ww,hh;
        for(t1=p1,t2=p2,ww=1;ww<=w;ww++)
          swap(f[t1=f[t1][0]][1],f[t2=f[t2][0]][1]);
        for(hh=1;hh<=h;hh++)
          swap(f[t1=f[t1][1]][0],f[t2=f[t2][1]][0]);
        for(t1=p1,t2=p2,hh=1;hh<=h;hh++)
          swap(f[t1=f[t1][1]][0],f[t2=f[t2][1]][0]);
        for(ww=1;ww<=w;ww++)
          swap(f[t1=f[t1][0]][1],f[t2=f[t2][0]][1]);
    }
    for(int i=1,p=lab[0][0];i<=n;i++)
    {
        for(int j=1,t=p=f[p][1];j<=m;j++)
            cout<
相关TAG标签
上一篇:C语言代码实现线性表、顺序表,及处理整型数据
下一篇:git版本的回退并提交到远程仓库
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站