選擇客棧 noip2011

在openjudge上做的題目,原來是2011年的=====。


題目:


麗江河邊有 n 家很有特色的客棧,客棧按照其位置順序從 1 到n 編號。每家客棧都按照某一種色調進行裝飾(總共 k 種,用整數 0 ~ k-1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。

兩位遊客一起去麗江旅遊,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位於兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過 p。
他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過 p元的咖啡店小聚。


 2<=n<=200000, 0<k<=50, 0<=p<=100, 0<=最低消費<=100


也就是找出所有對色調相同的旅館並且中間的最小費用小於p


首先想到的是 O(n^2)的,想到很容易,但20,000肯定爆炸。

然後想到的是拿一個數組保存相同色調的,可能好一點,萬一,萬一,萬一最壞顏色全部一樣(N^2)那就爆炸了。


其實這道題能用滾動數組優化,注意下面這點:

       如果 第i+1個色調爲k 的客棧 能訪問第i個色調爲k的客棧,那麼對於以後的所有色調爲k的客棧都可以訪問第i個色調爲k的客棧。

      簡單的說,如果這個客棧能被訪問,那麼後面所有的同類客棧都可以訪問他,畢竟後面到該客棧的費用必定 <=price[i] <= p。


我們只要2個數組

    一個用來保存可以直接訪問的。 

    一個用來保存無法訪問的;


如果發現連通,那麼 可以直接訪問的個數 += 無法訪問的個數(根據上面的推理,這些客棧都全部通了)


//其實一個也可以,只需要記錄色調k客棧出現的次數,然後每次 訪問個數 = 出現個數。


另外每個點每個顏色更新一下最短值。

這樣在O(nk)就解決了。

#include <iostream>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;

int n,k,p;
int direct[51];
int block[51];
int pre[51];


int main()
{
	memset(pre,0x3f,sizeof(pre));
	int ans = 0;
	cin >> n >> k >> p;
	int x = 0 , y;
	
	for (int i = 1 ; i <= n ; ++i)
	{
		cin >> x >> y;   
		if(pre[x] == inf)    //如果路徑無窮大 保存
		{                     //加上必通的 
		  block[x] = 1;      //累計數量=1 
		  pre[x] = y;        //最低費用爲y 
		  
		  for (int j = 0;j < k ;++j)
		    if (pre[j] != inf)
		      pre[j] = min (pre[j],y);  //如果費用存在,則更新最小費用 
		      
		  continue;          //繼續循環 
		 } 
		  
		  
		for (int j = 0;j < k ;++j)
		    if (pre[j] != inf)
		      pre[j] = min (pre[j],y);  //如果費用存在,則更新最小費用 
		    
			if(pre[x] <= p) //如果費用滿足要求,那麼對於後面的客棧,前面的路全通 
			 {
				direct[x] += block[x];
				block[x] = 1;  //不滿足數量爲 0 
				pre[x] = y;  //最小費用爲當前客棧 
			}
			else           //如果大於,則卡住 +1 
				block[x]++;
	    ans += direct[x];     //加上直接可以取的
	   
	}
    cout << ans << endl;
}



補:後來改了一下,改成一個數組,兩個數組真的囉嗦,直接設個計數器就簡單多了,還調整了下代碼,主代碼大概就20行左右!


#include <iostream>
#include <cstring>
#define inf 0x3f3f3f3f
using namespace std;

int n,k,p;
int direct[51];
int cnt[51];
int pre[51];

int main()
{
	memset(pre,0x3f,sizeof(pre));
	int ans = 0;
	cin >> n >> k >> p;
	int x = 0 , y;
	for (int i = 1 ; i <= n ; ++i)
	{
		cin >> x >> y;   
		cnt[x]++;
		if(pre[x] == inf) pre[x] = y;
		 for (int j = 0;j < k ;++j)
		    if (pre[j] != inf)
		      pre[j] = min (pre[j],y);  //如果費用存在,則更新最小費用 
		      
			if(pre[x] <= p) //如果費用滿足要求,那麼對於後面的客棧,前面的路全通 
			 {
				direct[x] = cnt[x] - 1;
				pre[x] = y;  //最小費用爲當前客棧 
			 }
				
	    ans += direct[x];     //加上直接可以取的
	}
    cout << ans << endl;
}




發佈了52 篇原創文章 · 獲贊 7 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章