1. 程式人生 > 其它 >商店購物題解

商店購物題解

商店購物!!!

- 請奆佬們潔身自好,好好打程式碼從我做起 -

題目大意:

在商店中,每一種商品都有一個價格

商店 把一個或多個商品組合起來降價銷售,形成優惠方案

編寫一個程式,計算顧客購買一定商品的花費,利用優惠使花費最少。

儘管有時候新增其他商品可以獲得更少的花費,但是你不能這麼做。


解析題目:

這道題就是五維暴力,但 易錯點很多,噁心,是道毒瘤題

不愧是IOI的真題

暴力,資料較小,且最多五種商品

注意!儘管有時候新增其他商品可以獲得更少的花費,但是你不能這麼做

比如你要買三個蘋果,兩根香蕉,花了11z

方案是三個蘋果,三根香蕉花了10z

那也不行,因為浪費了一根香蕉

(宣傳不浪費的IOI)

狀態:f(i,j,k,l,q)表示 買 i 的第一種商品 ,買 j 的第二種商品 ,買 k 的第三種商品 ,買 l 的第四種商品 ,買 q 的第五種商品 的最小花費

如果不足五種怎麼辦?其實不慌,比如如果有三種 ,l,q將一直等於0,不影響使用

我們還需要一個二維陣列p,p(i,j)表示第i種優惠裡商品j所需的數量。

模擬即可


詳細講解:

先來介紹一下沒什麼用快讀吧

C++ 中,讀入字元要比讀入數字快

因此,我們可以讀入字元,將其轉為數字

在一百萬次輸入後,快讀將比scanf快1秒

其實這道題不用快讀,是我打時不知道怎麼想的

inline int read() 
{
    int ans = 0;
    char c = getchar();
    while ((c < '0' || c > '9') )//篩掉空格、換行等 
	{
		c = getchar();
	}
    ans = c - '0';//正式開始讀入 
	c = getchar();
    while (c >= '0' && c <= '9') 
	{
		ans = (ans << 3) + (ans << 1);//位運算比正常計算快,這個位運算等價於ans*=10; 
		ans += c - '0'; 
		c = getchar();
	}
    return ans;
}//總之就生活小妙招了屬於是 

見樣例,雖然 只有5種,

但編號不一定是1~5,我們需要在輸入自行編號,一個h陣列即可,map會WA

由於一個編號會出現多次,要先判斷h[x]是否為0,是0才編號

	for(int i=1;i<=s;i++)//s是方案數
	{
		n=read();
		for(int j=1;j<=n;j++)
		{
			b=read();
			if(h[b]==0)h[b]=++tmp;//編號
			p[i][h[b]]=read();
		}
		money[i]=read();//money是 優惠方案的價錢 的意思 
	}

在下面也是一樣的

	for(int i=1;i<=b;i++)//b是我們要買的種類數
	{
		int x=read(); 
		if(h[x]==0)h[x]=++tmp;
		//同上,是0才編號 
		need[h[x]]=read(); //need表示我們一共需要多少個 
		old[h[x]]=read();//old 表示原價 
	}

接下來是初始化

因為f(i,j,k,l,q)表示買 i 的第一種商品 ,買 j 的第二種商品 ,買 k 的第三種商品 ,買 l 的第四種商品 ,買 q 的第五種商品 的最小花費

所以預設是全用原價

	for(int i=0;i<=need[1];i++)
	{
		for(int j=0;j<=need[2];j++)
		{
			for(int k=0;k<=need[3];k++)
			{
				for(int l=0;l<=need[4];l++)
				{
					for(int q=0;q<=need[5];q++)//五重暴力初始化,求出所有的原價
											   //注意也要考慮0,不買也不是不行 
					{
						 f[i][j][k][l][q]=old[1]*i+old[2]*j+old[3]*k+old[4]*l+old[5]*q;
					}						 
				}			 
			}			 
		} 		 
	} 	

誰寫的順口溜?


接下來是可怕的六重迴圈解析


	for(int m=1;m<=s;m++)
     {

程式碼:我裂開了

m表示當前考慮的方案

然後繼續看

我們要列舉i,j,k,l,q

對於範圍,不足 p[m]就不能實現方案了,超過need就浪費了

所以是p[m]~need

		for(int i=p[m][1];i<=need[1];i++)
		{
			for(int j=p[m][2];j<=need[2];j++)
			{
				for(int k=p[m][3];k<=need[3];k++)
				{
					for(int l=p[m][4];l<=need[4];l++)
					{
						for(int q=p[m][5];q<=need[5];q++)//從i到q都一樣,只是表示的 要買的東西 不同 

解析一下轉移方程

當求 f(i,j,k,l,q)時,

應該將其分解成子問題

顯然,我們只用考慮 賣完還需要的東西構成的子問題 加上 方案價格比較大小 即可


					{  
						if(f[i][j][k][l][q]>=f[i-p[m][1]][j-p[m][2]][k-p[m][3]][l-p[m][4]][q-p[m][5]]+money[m])
						{
					 		f[i][j][k][l][q]=f[i-p[m][1]][j-p[m][2]][k-p[m][3]][l-p[m][4]][q-p[m][5]]+money[m];
						}		
					}						 

別忘了括號

			}			 
		}			 
	} 		 
} 			
}

版權歸某鄧吖所有,禁止未經作者同意搬運!