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。
思路:这题实在太难,不会......
代码如下:
  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 /*===================================================================*/

 

 

posted @ 2015-02-22 17:19  Memoryヾノ战心  阅读(1225)  评论(0编辑  收藏  举报