题目大意:n*m矩阵,某些位置已经有一个数字,其他位置如何填,才能使数字之和最大?要求相邻两个数字之差不超过d。

要数字之和最大,填的数字越大越好。

对于一个空格,到底填多少呢?一时很难确定。

对于最小的数字a,周围填的数字越大越好,那就填a+d吧!填下去之后,如果与周围有冲突,那就填不了了:

1、如果周围原来是空的,那么这个数字不比a小,他之前的数字也不比a小,不可能发生冲突呢?

2、如果周围原来有预置的数字,那没办法了,因为他肯定是非常大的一个数,已经用最大的填也填不了。

大概就是这样,需要注意的是,输入数据允许重复,但不允许重复位置不同数值,而且数据有0。

方法一,用优先队列(堆)快速找到最小值,填周围的数字,时间复杂度,感觉比较容易超时。

#include <bits/stdc++.h>
using namespace std;
int F, S, D, c, n, m, i, j, k, ans, mo = 1e9 + 7;
int dx[]={-1, 1, 0, 0}, dy[]={0, 0, -1, 1};
int x, y, z, xx, yy, zz, mp[1005][1005], f[1005][1005];
struct XY{
    int x, y, z;
    bool operator < (const XY &A) const{
        return z > A.z;
    }
} t;
priority_queue <XY> q;
int ok(int x, int y, int z){
    if(x < 1 || x > n || y < 1 || y > m) return 0;
    if(f[x][y]) return 0;
    f[x][y] = 1;//避免零美味程度 
    int i, xx, yy;
    for(i=0; i<4; i++){
        xx = x + dx[i], yy = y + dy[i];
        if(f[xx][yy]){
            F |= abs(z-mp[xx][yy]) > D;
        }
    }
    return F == 0;
}
int main(){
    scanf("%d%d%d%d", &n, &m, &c, &D);
    for(i=1; i<=c; i++){
        scanf("%d%d%d", &x, &y, &z);
        if(f[x][y] && mp[x][y]!=z) F = 1;//输入数据允许重复 
        if(ok(x, y, z)) q.push((XY){x, y, mp[x][y] = z});
    }
    while(F==0 && q.size()){
        t = q.top(), q.pop();
        x = t.x, y = t.y, z = t.z, S++, ans = (ans+z)%mo;
        for(i=0; i<4; i++){
            xx = x+dx[i], yy = y+dy[i], zz = z+D;
            if(ok(xx, yy, zz)){
                q.push((XY){xx, yy, mp[xx][yy] = zz});
            }
        }
    }
    if(F == 0 && S == m*n) printf("%d\n", ans);
    else printf("PitayaCrying\n");
    return 0;
}

方法二:原来的2000多个数据先排序,后面填的数字必然单调递增,用单调队列,时间复杂度

#include <bits/stdc++.h>
#define N 1005
using namespace std;
int F, S, D, c, n, m, i, j, k, ans, mo = 1e9 + 7;
int dx[]={-1, 1, 0, 0}, dy[]={0, 0, -1, 1};
int x, y, z, xx, yy, zz, mp[N][N], f[N][N];
int da, db, qa, qb;
struct XY{
    int x, y, z;
    bool operator < (const XY &A) const{
        return z < A.z;
    }
} d[N*2], q[N*N], t;
int ok(int x, int y, int z){
    if(f[x][y]) return 0;//填过不再填 
    if(x < 1 || x > n || y < 1 || y > m) return 0;
    int i, xx, yy;
    for(i=0; i<4; i++){
        xx = x + dx[i], yy = y + dy[i];
        if(f[xx][yy]){
            F |= abs(z-mp[xx][yy]) > D;
        }
    }
    f[x][y] = 1;
    return F == 0;
}
int main(){
    scanf("%d%d%d%d", &n, &m, &c, &D);
    for(i=1; i<=c; i++){
        scanf("%d%d%d", &x, &y, &z);
        if(f[x][y] && mp[x][y]!=z) F = 1;//输入数据允许重复
        if(ok(x, y, z)) d[++db] = (XY){x, y, mp[x][y] = z};
    }
    sort(d+1, d+db+1);
    da = qa = 1;
    while(F==0 && (da<=db || qa<=qb)){
        if(da > db) t = q[qa++];
        else if(qa > qb) t = d[da++];
        else if(d[da] < q[qa]) t = d[da++];
        else t = q[qa++];
        x = t.x, y = t.y, z = t.z, S++, ans = (ans+z)%mo;
        for(i=0; i<4; i++){
            xx = x+dx[i], yy = y+dy[i], zz = z+D;
            if(ok(xx, yy, zz)){
                q[++qb] = (XY){xx, yy, mp[xx][yy] = zz};
            }
        }
    }
    if(F == 0 && S == m*n) printf("%d\n", ans);
    else printf("PitayaCrying\n");
    return 0;
}