UVA815 洪水(重慶一中高2018級信息學競賽測驗3) 解題報告

【問題描述】  (注意,本次的考試題目輸入輸出及數據範圍與UVA原題不太一樣,原題見UVA815 Flooded!,但思路一樣,同時下面有原題代碼)
  
  有一個n行m列的網格,每個格子是邊長爲10米的正方形,網格四周是無限高的牆壁,第i行第j列每個格子的海拔高度爲h[i][j]。現在網格中有T立方米的水,請你計算網格中的水平面的海拔高度,以及有水格子數目。注意,在網格中,所有有水格子的水平面的海拔高度相同,所以有水格子的數量爲海拔高度嚴格小於水平面高度的格子數目。
 
    
 【輸入格式】  
  
  第一行整數n和m,表示網格有n行m列。
  接下來是n行m列的矩陣,第i行第j列的數字爲對應格子的海拔高度h[i][j]。
  最後一行爲整數T,表示網格中水的體積。
 
    
 【輸出格式】  
   
  第一行爲一個實數,表示水平面的海拔高度,保留2位小數。
  第二行爲一個整數,表示有水格子的數目。
 
    
 【輸入樣例】   
   
3 3
25 37 45
51 12 34
94 83 27
10000 
 
    
 【輸出樣例】  
   
46.67
6
 
    
 【數據範圍】  
   
1<=n,m<=30 
0<=h[i][j]<=1 000 000
1<=T<=1 000 000 000
 
    
 【來源】  
  
《算法競賽》99頁 UVa815


 

做題思路(正解):拿到這道題,首先想到的便是貪心,貪心策略爲選出當前最矮的格子,看將這個格子填水到與第二矮的格子一樣高時,用的水是否達到輸入的水的體積,如果沒有,則繼續填下一個格子;如果達到或超過輸入水的體積,則可以直接計算出答案(用輸入的水的體積減去未填該格子時用的水的體積,再除以100*所填格子的數目,最後加上之前的水平面海拔高度(前一個填的格子的高度))。需要注意的是,可能把所有格子填水後,所用的水依然小於輸入的水的體積,此時需要單獨計算答案。其實,這道題也可以用二分猜答案的方法完成。


考試題目代碼:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=35;
int N,M,T;
int h[maxn*maxn]; //可以直接用一維數組存儲,方便排序
bool cmp(int aa,int bb) 
{
	return aa<bb;
}
int main()
{
	//freopen("flood.in","r",stdin);
	//freopen("flood.out","w",stdout);
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;i++)
	for(int j=1;j<=M;j++)
	scanf("%d",&h[(i-1)*M+j]);
	scanf("%d",&T);
	sort(h+1,h+1+M*N,cmp);  //按海拔高度由低到高排序
	int sum=0,cnt=0;
	double ans=0;
	for(int i=2;i<=N*M;i++)  //貪心算法
	{
		if(sum+(h[i]-h[i-1])*100*(1+cnt)<T)
		{
			cnt++; //記錄當前已填的格子數
			sum+=(h[i]-h[i-1])*100*cnt; //記錄當前用的水的體積
		}
		else
		{
			cnt++;
			ans=1.0*(T-sum)/100/cnt+h[i-1];
			break;
		}
	}
	if(ans==0)  //特殊判斷,如果所有格子都被填後,所用的水的體積仍小於輸入的水的體積
	{
		cnt++;
		ans=1.0*(T-sum)/100/cnt+h[N*M];
	}
	printf("%.2lf\n",ans);
	printf("%d\n",cnt);
	return 0;
}


原題代碼:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=35;
int N,M,T,tmp=0;
int h[maxn*maxn];
bool cmp(int aa,int bb)
{
	return aa<bb;
}
int main()
{
	freopen("flood.in","r",stdin);
	freopen("flood.out","w",stdout);
	while(1)
	{
		scanf("%d%d",&N,&M);
		if(N==0 && M==0)  break;
		tmp++;
		for(int i=1;i<=N;i++)
		for(int j=1;j<=M;j++)
		scanf("%d",&h[(i-1)*M+j]);
		scanf("%d",&T);
		sort(h+1,h+1+M*N,cmp);
		int sum=0,cnt=0;
		double ans=0;
		for(int i=2;i<=N*M;i++)
		{
			if(sum+(h[i]-h[i-1])*100*(1+cnt)<T)
			{
				cnt++;
				sum+=(h[i]-h[i-1])*100*cnt;
			}
			else
			{
				cnt++;
				ans=1.0*(T-sum)/100/cnt+h[i-1];
				break;
			}
		}
		if(ans==0)
		{
			cnt++;
			ans=1.0*(T-sum)/100/cnt+h[N*M];
		}
		printf("Region %d\n",tmp);
		printf("Water level is %.2lf meters.\n",ans);
		double ans1=1.0*cnt/(N*M);
		ans1=ans1*100;
		printf("%.2lf percent of the region is under water.\n",ans1);
		printf("\n");
	}
		return 0;
}

考後反思:拿到貪心算法的題目時,要找準貪心策略,同時自己的思維要嚴密,注意判斷特殊情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章