1. 程式人生 > >P2484 [SDOI2011]打地鼠

P2484 [SDOI2011]打地鼠

遊戲 由於 進行 == 必須 提示 span const 通過

\(\color{#0066ff}{ 題目描述 }\)

打地鼠是這樣的一個遊戲:地面上有一些地鼠洞,地鼠們會不時從洞裏探出頭來很短時間後又縮回洞中。玩家的目標是在地鼠伸出頭時,用錘子砸其頭部,砸到的地鼠越多分數也就越高。

遊戲中的錘子每次只能打一只地鼠,如果多只地鼠同時探出頭,玩家只能通過多次揮舞錘子的方式打掉所有的地鼠。你認為這錘子太沒用了,所以你改裝了錘子,增加了錘子與地面的接觸面積,使其每次可以擊打一片區域。如果我們把地面看做mn的方陣,其每個元素都代表一個地鼠洞,那麽錘子可以覆蓋RC區域內的所有地鼠洞。但是改裝後的錘子有一個缺點:每次揮舞錘子時,對於這 的區域中的所有地洞,錘子會打掉恰好一只地鼠。也就是說錘子覆蓋的區域中,每個地洞必須至少有1只地鼠,且如果某個地洞中地鼠的個數大於1,那麽這個地洞只會有1只地鼠被打掉,因此每次揮舞錘子時,恰好有R*C只地鼠被打掉。由於錘子的內部結構過於精密,因此在遊戲過程中你不能旋轉錘子(即不能互換R和C)。

你可以任意更改錘子的規格(即你可以任意規定R和C的大小),但是改裝錘子的工作只能在打地鼠前進行(即你不可以打掉一部分地鼠後,再改變錘子的規格)。你的任務是求出要想打掉所有的地鼠,至少需要揮舞錘子的次數。

Hint:由於你可以把錘子的大小設置為1*1,因此本題總是有解的。

$\color{#0066ff}{ 輸入格式 } $

第一行包含兩個正整數m和n;

下面m行每行n個正整數描述地圖,每個數字表示相應位置的地洞中地鼠的數量。

\(\color{#0066ff}{輸出格式}\)

輸出一個整數,表示最少的揮舞次數。

\(\color{#0066ff}{輸入樣例}\)

3 3
1 2 1
2 4 2
1 2 1

\(\color{#0066ff}{輸出樣例}\)

4

\(\color{#0066ff}{數據範圍與提示}\)

使用2*2的錘子,分別在左上、左下、右上、右下揮舞一次。

對於30%的數據,m,n<=5 ;

對於60%的數據,m,n<=30 ;

對於100%的數據,1<=m,n<=100 ,其他數據不小於0,不大於10^5 。

\(\color{#0066ff}{ 題解 }\)

枚舉矩形長寬然後暴力模擬即可

重要剪枝

因為每次會去掉R*L的價值

所以矩陣的和一定是R*L的倍數

還有個最優性剪枝

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int maxn = 120;
const int inf = 0x7fffffff;
LL mp[maxn][maxn], ls[maxn][maxn];
int n, m;
LL T;
int ans = inf;
void getans(LL x, LL y) {
    int tot = 0;
    LL v = T;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) 
            ls[i][j] = mp[i][j];
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) {
            int xx = i + x - 1;
            int yy = j + y - 1;
            if(xx > n || yy > m) continue;
            LL min = inf;
            for(int p = i; p <= xx; p++)
                for(int q = j; q <= yy; q++) {
                    min = std::min(min, ls[p][q]);
                }
            if(!min) continue;
            for(int p = i; p <= xx; p++)
                for(int q = j; q <= yy; q++)
                    ls[p][q] -= min;
            tot += min;
            v -= min * x * y;
        }
    if(!v) ans = std::min(ans, tot);
}

int main() {
    n = in(), m = in();
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++) 
            T += (mp[i][j] = in());
    ans = T;
    for(int i = n; i >= 1; i--)
        for(int j = m; j >= 1; j--) {
            if(T % (i * j)) continue;
            if(T / (i * j) >= ans) continue;
            getans(i, j);
        }
    printf("%d\n", ans);
    return 0;
}

P2484 [SDOI2011]打地鼠