P2484 [SDOI2011]打地鼠
阿新 • • 發佈:2019-02-04
遊戲 由於 進行 == 必須 提示 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]打地鼠