NOIP2014-普及组复赛-第四题-子矩阵

题目描述 Description

给出如下定义:

1. 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与列的相对顺序)被称为原矩阵的一个子矩阵。

例如,下面左图中选取第2、4行和第2、4、5列交叉位置的元素得到一个2*3的子矩阵如右图所示。

9   3   3   3   9

9   4   8   7   4

1   7   4   6   6

6   8   5   6   9

7   4   5   6   1

的其中一个2*3的子矩阵是
4   7   4
8   6   9

2. 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的。

3. 矩阵的分值:矩阵中每一对相邻元素之差的绝对值之和。

本题任务:给定一个n行m列的正整数矩阵,请你从这个矩阵中选出一个r行c列的子矩阵,使得这个子矩阵的分值最小,并输出这个分值。

(本题目为2014NOIP普及T4)

输入输出格式 Input/output

输入格式:
第一行包含用空格隔开的四个整数n,m,r,c,意义如问题描述中所述,每两个整数之间用一个空格隔开。

接下来的n行,每行包含m个用空格隔开的整数,用来表示问题描述中那个n行m列的矩阵。
输出格式:
输出共1行,包含1个整数,表示满足题目描述的子矩阵的最小分值。

输入输出样例 Sample input/output

样例测试点#1

输入样例:

5 5 2 3
9 3 3 3 9
9 4 8 7 4
1 7 4 6 6
6 8 5 6 9
7 4 5 6 1

输出样例:

6

样例测试点#2

输入样例:

7 7 3 3
7 7 7 6 2 10 5
5 8 8 2 1 6 2
2 9 5 5 6 1 7
7 9 3 6 1 7 8
1 9 1 4 7 8 8
10 5 9 1 1 8 10
1 3 1 5 4 8 6

输出样例:

16

说明 description

【输入输出样例1说明】

该矩阵中分值最小的2行3列的子矩阵由原矩阵的第4行、第5行与第1列、第3列、第4列交叉位置的元素组成,为
6  5  6 
7  5  6
,其分值为
|6−5| + |5−6| + |7−5| + |5−6| + |6−7| + |5−5| +  |6−6| =6。

【输入输出样例2说明】

该矩阵中分值最小的3行3列的子矩阵由原矩阵的第4行、第5行、第6行与第2列、第6列、第7列交叉位置的元素组成,选取的分值最小的子矩阵为
9 7 8
9 8 8
5 8 10

【数据说明】

对于50%的数据,1 ≤ n ≤ 12,1 ≤ m ≤ 12,矩阵中的每个元素1 ≤ a[i][j] ≤ 20;

对于100%的数据,1 ≤ n ≤ 16,1 ≤ m ≤ 16,矩阵中的每个元素1 ≤ a[i][j] ≤ 1,000,
1 ≤ r ≤ n,1 ≤ c ≤ m。

思路:这题实在太难,不会......

代码如下(本代码来自:http://blog.csdn.net/cnyali/article/details/40998345):

  1 #include       <map>
  2 #include       <set>
  3 #include     <stack>
  4 #include     <cmath>
  5 #include     <ctime>
  6 #include     <queue>
  7 #include    <cstdio>
  8 #include    <vector>
  9 #include    <string>
 10 #include    <bitset>
 11 #include   <cstring>
 12 #include   <cstdlib>
 13 #include  <iostream>
 14 #include <algorithm>
 15 using namespace std;
 16
 17 #ifndef unix
 18     #define lld "%I64d"
 19     #define llu "%I64u"
 20 #else
 21     #define lld "%lld"
 22     #define llu "%llu"
 23 #endif
 24
 25 #define FOR(a,b,c)  for(int (a)=b;(a)<=(c);++(a))
 26 #define FORD(a,b,c) for(int (a)=b;(a)>=(c);--(a))
 27 #define FORV(a,t,b) for(vector<t>::iterator a=b.begin();a!=b.end();++a)
 28 #define MAX(a,b)                   a=max(a,b)
 29 #define MIN(a,b)                   a=min(a,b)
 30 #define BLA                      printf("\n")
 31 #define pb                          push_back
 32 #define mp                          make_pair
 33 #define gc                            getchar
 34 #define RT                             return
 35 #define BB                             second
 36 #define AA                              first
 37 #define bk                              break
 38 #define LINF             0x3f3f3f3f3f3f3f3fll
 39 #define INF                        0x3f3f3f3f
 40 #define eps                              1e-8
 41 #define DINF                             1e20
 42
 43 //#define Generator
 44
 45 typedef long long           ll;
 46 typedef unsigned            ui;
 47 typedef unsigned long long ull;
 48 typedef pair<int,int>      pii;
 49 typedef pair<ll ,ll >      pll;
 50
 51 const int MAXN= 0;
 52 const int MOD = 0;
 53
 54 template <class T> inline void CLR(T &g)             {T t;swap(t,g);}
 55 template <class T> inline void CLR(T &g,int a){memset(g,a,sizeof g);}
 56 template <class T> inline void CPY(T &a,T &b) {memcpy(a,b,sizeof a);}
 57 template <class T> inline bool inr(T a,T b,T c)  {RT (a>=b && a<=c);}
 58 inline int acc(int a,int b)                    {RT !!(a & (1<<b-1));}
 59 inline int fil(int a,int b,int c)    {RT a & ~(1<<b-1) | (1<<b-1)*c;}
 60
 61 int N, M, K, Q, R, C;
 62
 63 int a[20][20];
 64 int f[20][20];//f[i][j]表示 已经选择i列 上一列是j
 65 int sum[20], d[20], csum[20][20];
 66 /*========================================================*/
 67 int main()
 68 {
 69     #ifndef Generator
 70     #ifndef ONLINE_JUDGE
 71     #endif
 72     #endif                                                         //真
 73     #ifdef Generator                                               //正
 74         freopen("input.txt","w",stdout);                           //有
 75         srand((ui)time(NULL));                                     //用
 76     #endif                                                         //的
 77     int T, o=0;                                                    //在
 78     scanf("%d%d%d%d", &N, &M, &R, &C);                             //这
 79     FOR(i, 1, N)                                                   //里
 80         FOR(j, 1, M)
 81             scanf("%d", &a[i][j]);
 82     int ans=INF;
 83     FOR(i, 1, (1<<N)-1){//枚举哪些行被选入矩阵
 84         int cnt=0;
 85         FOR(j, 1, N)
 86             if (acc(i, j)) d[++cnt]=j;
 87         if (cnt != R) continue;
 88         FOR(j, 1, M){
 89             sum[j]=0;
 90             FOR(k, 1, R-1)
 91                 sum[j] += abs(a[d[k]][j]-a[d[k+1]][j]);
 92         }
 93         FOR(j, 1, M)
 94             FOR(k, j+1, M){
 95                 csum[j][k]=0;
 96                 FOR(l, 1, R)
 97                     csum[j][k] += abs(a[d[l]][j]-a[d[l]][k]);
 98             }
 99         CLR(f, 0x3f);
100         f[0][0]=0;
101         FOR(j, 1, C){
102             FOR(k, 1, M){
103                 int tot=0;
104                 FOR(l, 0, k-1)
105                     MIN(f[j][k], f[j-1][l]+csum[l][k]+sum[k]);
106             }
107         }
108         FOR(j, 1, M)
109             MIN(ans, f[C][j]);
110     }
111     printf("%d\n", ans);
112     RT 0;
113 }
114 /*===================================================================*/
时间: 2024-10-26 09:14:44

NOIP2014-普及组复赛-第四题-子矩阵的相关文章

NOIP2010-普及组复赛-第四题-三国游戏

题目描述 Description 小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏.  在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有 N 位武将(N为偶数且不小于 4),任意两个武将之间有一个“默契值”,表示若此两位武将作为一对组合作战时,该组合的威力有多大.游戏开始前,所有武将都是自由的(称为自由武将,一旦某个自由武将被选中作为某方军队的一员,那么他就不再是自由武将了),换句话说,所谓的自由武将不属于任何一方. 游戏开始,小涵和计算机要从自由武将中挑选武将组成自

博弈论(noip普及组2010第四题 三国游戏)

小涵很喜欢电脑游戏,这些天他正在玩一个叫做<三国>的游戏. 在游戏中,小涵和计算机各执一方,组建各自的军队进行对战.游戏中共有 N 位武将(N为偶数且不小于 4),任意两个武将之间有一个“默契值”,表示若此两位武将作为一对组合作战时,该组合的威力有多大.游戏开始前,所有武将都是自由的(称为自由武将,一旦某个自由武将被选中作为某方军队的一员,那么他就不再是自由武将了),换句话说,所谓的自由武将不属于任何一方. 游戏开始,小涵和计算机要从自由武将中挑选武将组成自己的军队,规则如下:小涵先从自由武将

C++ P1318 Jam的计数法(NOIP2006普及组复赛第3题)

#include<iostream>#include<cstdio>using namespace std; int s,t,w,a[30],time=5;char c[30];bool ok;//ok表示是否找到规定集合: void data_in()//使用位向量法: { scanf("%d%d%d",&s,&t,&w); scanf("%s",c); for(int i=0;i<w;i++) a[c[i]-

[NOIP2014普及组]螺旋矩阵

题目地址: ayyzvijos:http://pingce.ayyz.cn/vijos/Problem_Show.asp?id=2017 vijos:https://vijos.org/p/1913 COGS:http://218.28.19.228/cogs/problem/problem.php?pid=1811 题目来源:NOIP2014普及组第三题 问题分析:这道题的内容很易懂,而且容易实现,即直接构造出一个螺旋矩阵,输出对应位置即可.这样的方法大概可以过掉50%的数据.但是,对于100

[NOIP2014普及组]比例简化

题目地址: ayyzvijos:http://pingce.ayyz.cn/vijos/Problem_Show.asp?id=2016 vijos:https://vijos.org/p/1912 COGS:http://218.28.19.228/cogs/problem/problem.php?pid=1810 题目来源:NOIP2014普及组第二题 问题分析:题目描述很长,归纳起来,大意就是: 在区间[1,L]内求出2个数A’.B’,这两个数满足: 一.gcd(A’,B’)=1,即A’和

[NOIP2014普及组]珠心算测验

题目地址: ayyzvijos:http://pingce.ayyz.cn/vijos/Problem_Show.asp?id=2015 vijos:https://vijos.org/p/1911 COGS:http://218.28.19.228/cogs/problem/problem.php?pid=1809 题目来源:NOIP2014普及组第一题 问题分析:作为普及组的第一题,这个难度是可以的,而且有坑点.初步读题,我们会想到这样一种情况: count.in count.out 5 1

NOIP2005-普及组复赛-第三题-采药

题目描述 Description 辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断他的资质,给他出了一个难题.医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值.我会给你一段时间,在这段时间里,你可以采到一些草药.如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大.” 如果你是辰辰,你能完成这个任务吗? 输入输出格式 Input/output 输入格式:输

NOIP2016普及组复赛解题报告

提高组萌新,DAY1DAY2加起来骗分不到300,写写普及组的题目聊以自慰. (附:洛谷题目链接 T1:https://www.luogu.org/problem/show?pid=1909 T2:https://www.luogu.org/problem/show?pid=2010 T3:https://www.luogu.org/problem/show?pid=2058 T4:https://www.luogu.org/problem/show?pid=2119) 不得不说,亲历了14.1

普及组2006第三题jam的计数法

P1061 Jam的计数法 题目描述 Jam是个喜欢标新立异的科学怪人.他不使用阿拉伯数字计数,而是使用小写英文字母计数,他觉得这样做,会使世界更加丰富多彩. 在他的计数法中,每个数字的位数都是相同的(使用相同个数的字母),英文字母按原先的顺序,排在前面的字母小于排在它后面的字母.我们把这样的"数字"称为Jam数字.在Jam数字中,每个字母互不相同,而且从左到右是严格递增的.每次,Jam还指定使用字母的范围,例如,从2到10,表示只能使用{b,c,d,e,f,g,h,i,j}这些字母.