程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> BZOJ 2241([SDOI2011]打地鼠-二分判斷+貪心)

BZOJ 2241([SDOI2011]打地鼠-二分判斷+貪心)

編輯:C++入門知識

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

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

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

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

 

Input
 第一行包含兩個正整數M和N;

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

 

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

 

Sample Input
3 3

1 2 1

2 4 2

1 2 1


Sample Output

4

【樣例說明】

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

【數據規模和約定】


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

 


二分判斷+貪心

 

 

[cpp]
#include<cstdio>  
#include<cstring>  
#include<cstdlib>  
#include<algorithm>  
#include<functional>  
#include<iostream>  
#define MAXN (100+10)  
#define INF (1000000000)  
#define For(i,n) for(int i=1;i<=n;i++)  
using namespace std; 
int n,m,a[MAXN][MAXN],a2[MAXN][MAXN]; 
int is_ok(int l,int r) 

    memcpy(a2,a,sizeof(a)); 
    int sum=0; 
    For(i,n-l+1) For(j,m-r+1) 
        if(a2[i][j]) 
        { 
            int delta=a2[i][j];sum+=delta; 
            for (int k=i;k<=i+l-1;k++) 
                for (int k2=j;k2<=j+r-1;k2++) 
                    if (a2[k][k2]<delta) return 0; 
                    else a2[k][k2]-=delta; 
        } 
    return sum; 

int main() 

    scanf("%d%d",&n,&m); 
    int cnt=0,ans=0; 
    For(i,n) For(j,m) {scanf("%d",&a[i][j]);cnt+=a[i][j];} 
    For(i,n) For(j,m)  
    { 
        if (i*j<ans) continue; 
        if (!(cnt%(i*j))&&is_ok(i,j)*i*j==cnt) 
        { 
            ans=i*j; 
        }        
    } 
    cout<<cnt/ans<<endl; 
    return 0; 

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#define MAXN (100+10)
#define INF (1000000000)
#define For(i,n) for(int i=1;i<=n;i++)
using namespace std;
int n,m,a[MAXN][MAXN],a2[MAXN][MAXN];
int is_ok(int l,int r)
{
 memcpy(a2,a,sizeof(a));
 int sum=0;
 For(i,n-l+1) For(j,m-r+1)
  if(a2[i][j])
  {
   int delta=a2[i][j];sum+=delta;
   for (int k=i;k<=i+l-1;k++)
    for (int k2=j;k2<=j+r-1;k2++)
     if (a2[k][k2]<delta) return 0;
     else a2[k][k2]-=delta;
  }
 return sum;
}
int main()
{
 scanf("%d%d",&n,&m);
 int cnt=0,ans=0;
 For(i,n) For(j,m) {scanf("%d",&a[i][j]);cnt+=a[i][j];}
 For(i,n) For(j,m)
 {
  if (i*j<ans) continue;
  if (!(cnt%(i*j))&&is_ok(i,j)*i*j==cnt)
  {
   ans=i*j;
  }  
 }
 cout<<cnt/ans<<endl;
 return 0;
}

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved