题目描述 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 /*===================================================================*/