【解题报告】 洛谷 P3492 [POI2009]TAB-Arrays

这题是我随机跳题的时候跳到的。写完这道题之后,顺便看了一下题解,发现只有一篇题解,所以就在这里顺便写一个解题报告了。

首先当然是题目链接

顺便贴一下csdn的网址

题目描述

给出两个n*m的矩阵,保证每个矩阵内元素互不相同且权值均在[-106,106]之间,请能否把其中一个矩阵通过若干次交换两行或者交换两列的操作变成另外一个矩阵。

输入输出格式

输入格式

第一行是一个整数T,表示有T组数据。

每一组数据的第一行是两个整数n和m,表示两个矩阵的大小是n行m列。接下来2*n行里面,每一行有m个数,前n行是第一个矩阵,后n行是第二个矩阵。话说有一点很奇怪,不知道为什么,题目没有给出数据范围,我还是根据内存空间限制算出我能用多少空间的。

输出格式

对于每一组数据,输出一行。若两个矩阵能够通过变换得到对方,则输出TAK,否则,输出NIE

输入输出样例

输入

2

4 3

1 2 3

4 5 6

7 8 9

10 11 12

11 10 12

8 7 9

5 4 6

2 1 3

2 2

1 2

3 4

5 6

7 8

输出

TAK

NIE

解题思路

我们先想一下另外一个问题:现在给你两个数组,问你:是否能把其中一个数组通过若干次交换两个元素的位置变成另外一个数组。

这个问题有一个简单粗暴的做法。对两个数组各自排序,看排序之后的两个数组是否完全相等即可。如,数组[1,4,3,5,6,7]和数组[4,3,6,1,7,5],他们排序过后都是同样的数组[1,3,4,5,6,7],所以这两个数组就可以通过若干次交换两个元素变成另外一个数组。(因为排序的过程就是不断地交换两个元素的位置,如果两个数组A,B都可以通过交换两个元素的位置变成同一个数组C(也就是这个排序之后的数组),那么其中一个数组A也必然可以变成排序之后的数组C,然后数组C再变成另外一个数组B)

上面那个方法可行的原因就在于:他们都可以变成一个排好序的数组,只要比较两个排好序的数组是否相等就可以了。而矩阵看起来不能这么干的原因就在于:你好像不能给他排序。

那么,我们回来我们现在这道题。我们通过仔细地思考,不难发现一个有趣的事实:无论是交换两行,还是交换两列,交换前后,本来在同一列的元素依然在同一列,本来在同一行的元素依然在同一行。只不过,经过交换之后,同一行或则同一列的元素的相对位置会改变而已。

所以,我们有这么一个想法:首先,把最小的一个元素放在左上角,然后分别以第一行为关键字和第一列为关键字对它进行排序。然后比较两个排好序之后的矩阵是否相等。

具体做法如下:

具体做法

  1. 把矩阵中最小的一个数通过变换放到矩阵的最左上角。(对两个矩阵都进行同样的操作,下面也是一样)
  2. 以矩阵的第一行为关键字,利用变换,使得第一行的数字有序(从大到小,或者从小到大)
  3. 以矩阵的第一列为关键字,利用变换,使得第一列的数字有序(从大到小,或者从小到大)
  4. 比较两个矩阵经过上述两个变换之后是否完全相等。

下面就是我的代码。

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2500;
const int INF=100000000;
struct ary
{
int n[N];
bool operator<(const ary &b)const
{
return n[1]<b.n[1];
}
};
ary a[N],b[N],c[N],d[N];
int main()
{
int test_num;
scanf("%d",&test_num);
while(test_num--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i].n[j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&b[i].n[j]);
int x=0,ma=INF;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i].n[j]<ma)
{
x=j;
ma=a[i].n[j];
}
}
}
for(int i=1;i<=n;i++)
{
int temp=a[i].n[1];
a[i].n[1]=a[i].n[x];
a[i].n[x]=temp;
}
sort(a+1,a+1+n);
ma=INF;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(b[i].n[j]<ma)
{
x=j;
ma=b[i].n[j];
}
}
}
for(int i=1;i<=n;i++)
{
int temp=b[i].n[1];
b[i].n[1]=b[i].n[x];
b[i].n[x]=temp;
}
sort(b+1,b+1+n);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
c[i].n[j]=a[j].n[i];
d[i].n[j]=b[j].n[i];
}
}
sort(c+1,c+1+m);
sort(d+1,d+1+m);
int flag=0;
for(int i=1;i<=m;i++)
{
if(flag) break;
for(int j=1;j<=n;j++)
{
if(c[i].n[j]!=d[i].n[j])
{
flag=1;
break;
}
}
}
if(flag)
{
printf("NIE\n");
}
else printf("TAK\n");
}
return 0;
}

【解题报告】 洛谷 P3492 [POI2009]TAB-Arrays的更多相关文章

  1. 洛谷 P3486 [POI2009]KON-Ticket Inspector

    P3486 [POI2009]KON-Ticket Inspector 题目描述 Byteasar works as a ticket inspector in a Byteotian Nationa ...

  2. 解题笔记-洛谷-P1010 幂次方

    0 题面 题目描述 任何一个正整数都可以用2的幂次方表示.例如 137=2^7+2^3+2^0 同时约定方次用括号来表示,即a^b 可表示为a(b). 由此可知,137可表示为: 2(7)+2(3)+ ...

  3. 解题:洛谷4721 [模板]分治FFT

    题面 这是CDQ入门题,不要被题目名骗了,这核心根本不在不在FFT上啊=.= 因为后面的项的计算依赖于前面的项,不能直接FFT.所以用CDQ的思想,算出前面然后考虑给后面的贡献 #include< ...

  4. 解题:洛谷4314 CPU监控

    题面 线段树·二重标记(什么鬼 用(a,b)标记表示先执行+a操作,然后对b取max,维护历史/当前最大值和历史/当前标记.然后我们发现区间加$x$就是$(x,-inf)$,区间赋$x$就是$(-in ...

  5. 解题:洛谷4178 Tree

    题面 重(新)学点分治中...... 普通的点分治一般这几步: 1.找重心 2.从重心开始DFS,得到信息 3.统计经过重心的路径 4.分别分治几棵子树,继续这个过程 然后是常见的(制杖的我的)一些疑 ...

  6. 解题:洛谷2093 JZPFAR

    题面 初见K-D Tree 其实这样的题(欧几里得距离第$x$近点对)不应该用K-D Tree做,因为会被构造数据卡成$O(n^2)$,随机的另说. 但是并没有找到合适的K-D Tree的题(区域统计 ...

  7. 解题:洛谷 p1858 多人背包

    题面 设$dp[i][j]$表示容量为$i$时的第$j$优解,因为是优解,肯定$dp[i][j]$是随着$j$增大不断递减的,这样的话对于一个新加进来的物品,它只可能从两个容量的转移的前$k$优解中转 ...

  8. 解题:洛谷2633 Count on a tree

    题面 在树上建主席树...... 每个点从父亲那里建过来,最后建出来就是从根到$i$这条链上的主席树,查询的时候一边差分一边查询 ($cmt[u]+cmt[v]-cmt[lca(u,v)]-cmt[a ...

  9. 解题:洛谷2257 YY的GCD

    题面 初见莫比乌斯反演 有一个套路是关于GCD的反演经常设$f(d)=\sum_{gcd(i,j)==d},g(d)=\sum_{d|gcd(i,j)}$,然后推推推 $\sum\limits_{i= ...

随机推荐

  1. Centos 7 nginx-1.12.0编译安装

    参考:http://www.nginx.cn/install 也不知道我的系统是否有这些依赖包,试试吧?缺少哪些我就装哪些吧,多踏点坑总是能学到点东西的.   获取nginx包 http://ngin ...

  2. VBS调用Windows API函数

    Demon's Blog 忘记了,喜欢一个人的感觉 Demon's Blog  »  程序设计  »  VBS调用Windows API函数 « 用VBS修改Windows用户密码 在VB中创建和使用 ...

  3. srm 539

    http://mlz000.github.io/2015/07/15/srm-539/ 250 Description: 从若干个盒子中随意选择几个装石头.每一个盒子容量都有上下限,一旦选择使用某个盒 ...

  4. C++中stringstream ostringstream istringstream使用方式

    C++引入了ostringstream.istringstream.stringstream这三个类,要使用他们创建对象就必须包括sstream.h头文件. istringstream类用于运行C++ ...

  5. 1732 Fibonacci数列 2

    1732 Fibonacci数列 2  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 在“1250 F ...

  6. Dictionary<string, string>是一个泛型使用说明

    Dictionary<string, string>是一个泛型使用说明 Posted on 2010-08-05 15:03 moss_tan_jun 阅读(2273) 评论(0) 编辑  ...

  7. Hyper-v 3.0 安装centos6.3

    Hyper-v 3.0 安装centos6.3 我们说到hyper-v3.0就想到了windows8.windows2012:我们也知道在windows8.windows2012上安装centos系统 ...

  8. pcntl研究

    虽说php用于并发计算有点山寨,但总比没有强把.(有问题请指正) 下面是pcntl多线程的例子.(只能用于cli模式,而且只能用于linux环境) <?php $starttime=microt ...

  9. VUE移动端禁止双手放大缩小

    //index.html <meta name="viewport" content="width=device-width,initial-scale=1.0,u ...

  10. 解决微信H5页面软键盘弹起后页面下方留白的问题(iOS端)

    前言:微信H5项目,ios端出现了软键盘输完隐藏后页面不会回弹,下方会有一大块留白 最近微信和ios都有版本升级,不知道是哪边升级造成的,但是经过测试,软键盘收起后,再滚动一下页面,下面的留白就会消失 ...