B1047 理想的正方形 RMQ
大家吸取我的教训,想好再写。我码了好长时间,最后发现算法处理的是另一个问题,我处理的是正方形情况的,才能用我优化之后的记忆化搜索,然而矩形就凉了。
先看一下题吧:
Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值 的差最小。 Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数。每 行相邻两数之间用一空格分隔。 100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000 Output 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值。 Sample Input 5 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2 1 1 2 2 2 Sample Output 1 HINT Source
我的反面教材代码:
#include<iostream> #include<cstdio> #include<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } int a,b,n; int p[1010][1010]; int f[1010][1010][15][3]; int l[15]; void dfs(int o,int x1,int y1,int x2,int y2) { if(f[x1][y1][o][1] != -1) return; if(x1 == x2 && y1 == y2) { f[x1][y1][o][1] = p[x1][y1]; f[x1][y1][o][0] = p[x1][y1]; return; } int minn = INF; int maxn = 0; dfs(o + 1,x1,y1,x1 + l[o],y1 + l[o]); dfs(o + 1,a - l[o],y1,a,y1 + l[o]); dfs(o + 1,x1,b - l[o],x1 + l[o],b); dfs(o + 1,a - l[o],b - l[o],a,b); // printf("%d %d %d %d\n",a - l[o],b - l[o],a,b); maxn = max(maxn,f[x1][y1][o + 1][1]); minn = min(minn,f[x1][y1][o + 1][0]); maxn = max(maxn,f[a - l[o]][y1][o + 1][1]); minn = min(minn,f[a - l[o]][y1][o + 1][0]); maxn = max(maxn,f[x1][b - l[o]][o + 1][1]); minn = min(minn,f[x1][b - l[0]][o + 1][0]); maxn = max(maxn,f[a - l[o]][b - l[o]][o + 1][1]); minn = min(minn,f[a - l[o]][b - l[o]][o + 1][0]); f[x1][y1][o][1] = maxn; f[x1][y1][o][0] = minn; return; } int main() { memset(f,-1,sizeof(f)); read(a);read(b);read(n); duke(i,1,a) { duke(j,1,b) read(p[i][j]); } int k = n,len = 0; while(k > 1) { k = ceil(k / 2); l[++len] = k; // cout<<k<<endl; } duke(i,1,a - n) duke(j,1,b - n) dfs(1,i,j,i + n,j + n); printf("%d %d\n",f[1][1][1][1],f[1][1][1][0]); return 0; } /* 5 4 2 1 2 5 6 0 17 16 0 16 17 2 1 2 10 2 1 1 2 2 2 */
然后就凉了,懒得写了,用二维的RMQ搞一下,抄了个比较清晰的代码。。。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int INF = 1000000000; const int maxm = 1000 + 100; const int maxn = 100 + 10; const int maxlog = 10; int a, b, n; int logn; int grid[maxm][maxm]; int maxv[maxm][maxm], minv[maxm][maxm]; int query (int x, int y) { int _max = 0, _min = 0; _max = max(maxv[x][y], max(maxv[x+n-(1<<logn)][y+n-(1<<logn)], max(maxv[x+n-(1<<logn)][y], maxv[x][y+n-(1<<logn)]))); _min = min(minv[x][y], min(minv[x+n-(1<<logn)][y+n-(1<<logn)], min(minv[x+n-(1<<logn)][y], minv[x][y+n-(1<<logn)]))); return _max - _min; } int main () { // freopen("in.txt", "r", stdin); cin >> a >> b >> n; for (int i = 0; i < a; i++) for (int j = 0; j < b; j++) { scanf("%d", &grid[i][j]); maxv[i][j] = minv[i][j] = grid[i][j]; } for (logn = 0; ((1<<(logn+1)) <= n); logn++); for (int k = 0; k < logn; k++) for (int i = 0; i+(1<<k) < a; i++) for (int j = 0; j+(1<<k) < b; j++) { maxv[i][j] = max(maxv[i][j], max(maxv[i+(1<<k)][j+(1<<k)], max(maxv[i+(1<<k)][j], maxv[i][j+(1<<k)]))); minv[i][j] = min(minv[i][j], min(minv[i+(1<<k)][j+(1<<k)], min(minv[i+(1<<k)][j], minv[i][j+(1<<k)]))); } int ans = INF; for (int i = 0; i <= a-n; i++) for (int j = 0; j <= b-n; j++) ans = min(ans, query(i, j)); cout << ans; return 0; }
唉,后悔啊。。。
只想找一个不会伤害我的人