非常可樂 九度 OJ 1457

2021-09-21 18:26:39 字數 2790 閱讀 6613

時間限制:1 秒 記憶體限制:32 兆 特殊判題:否

題目描述:

大家一定覺得運動以後喝可樂是一件很愜意的事情,但是 seeyou 卻不這麼認為。因為每次當 seeyou 買了可樂以後,阿牛就要求和 seeyou 一起分享這一瓶可樂,而且一定要喝的和 seeyou 一樣多。但 seeyou 的手中只有兩個杯子,它們的容量分別是 n 毫公升和 m 毫公升。可樂的體積為 s (s<101)毫公升(正好裝滿一瓶) ,它們三個之間可以相互倒可樂 (都是沒有刻度的,且 s==n+m,101>s>0,n>0,m>0) 。聰明的 acmer 你們說他們能平分嗎?如果能請輸出倒可樂的最少的次數,如果不能輸出"no"。

輸入:三個整數 : s 可樂的體積 , n 和 m 是兩個杯子的容量,以"0 0 0"結束。

輸出:如果能平分的話請輸出最少要倒的次數,否則輸出"no"。

樣例輸入:

7 4 3

4 1 3

0 0 0

樣例輸出:no3

這是乙個非常能夠說明狀態搜尋含義的題。題面中絲毫沒有涉及到圖的概念,也沒有給出任何圖模型。那麼,它也能進行搜尋麼?答案是肯定的,搜尋的途徑即是對狀態進行搜尋。

使用四元組(x,y,z,t)來表示乙個狀態,其中 x、y、z 分別表示三個瓶子中的可樂體積,t 表示從初始狀態到該狀態所需的杯子間互相傾倒的次數。狀態間的相互擴充套件,就是任意四元組經過瓶子間的相互傾倒而得到若干組新的四元組的過程。這樣,當平分的狀態第一次被搜尋出來以後,其狀態中表示的杯子傾倒次數即是所求。同樣的,由於要搜尋的是最少倒杯子次數,若四元組(x,y,z,t)中 t 並不是得到體積組 x、y、z 的最少倒杯子次數,那麼該狀態為無效狀態,將其捨棄。

#include #include using namespace std;

struct n;

queueq;//佇列

bool mark[101][101][101];

//對體積組(x,y,z)進行標記,即只有第一次得到包含

//體積組(x,y,z)的狀態為有效狀態,其餘的捨去

void atob(int &a,int sa,int &b,int sb)else

}int bfs(int s,int n,int m)

a=now.a;

b=now.b;

c=now.c;//重置a,b,c為未傾倒前的體積

atob(b,n,a,s);//由b傾倒向a

if(mark[a][b][c]==false)

a=now.a;

b=now.b;

c=now.c;

atob(a,s,c,m);//由a傾倒向c

if(mark[a][b][c]==false)

a=now.a;

b=now.b;

c=now.c;

atob(c,m,a,s);//由c傾倒向a

if(mark[a][b][c]==false)

a=now.a;

b=now.b;

c=now.c;

atob(b,n,c,m);//由b傾倒向c

if(mark[a][b][c]==false)

a=now.a;

b=now.b;

c=now.c;

atob(c,m,b,n);//由c傾倒向b

if(mark[a][b][c]==false)

}return -1;

}int main()

for(int i=0;i<=s;i++)

}}//初始化狀態

n tmp;

tmp.a=s;

tmp.b=0;

tmp.c=0;

tmp.t=0;//初始時狀態

while(q.empty()==false)q.pop();//清空佇列中狀態

q.push(tmp);//將初始狀態放入佇列

mark[s][0][0]=true;//標記初始狀態

int rec=bfs(s,n,m);//廣度優先搜尋

if(rec==-1)else

}return 0;

}

可見,與動態規劃問題一樣,廣度優先搜尋的關鍵也是確定狀態。只有確定了需要搜尋的狀態,才能更好的進行搜尋活動。同時,廣度優先搜尋的複雜度也與狀態的數量有關。

由於捨棄了很多無效的狀態,那麼其時間複雜度與有效狀態正相關。如本題所有可能出現的狀態為 100100100 個,即每個體積組對應乙個有效狀態,所以其複雜度也大致為這個數量級,在進行廣搜之前要判斷其複雜度是否符合要求。

最後,總結廣度優先搜尋的幾個關鍵字:

1.狀態。確定求解問題中的狀態。通過狀態的轉移擴充套件,查詢遍歷所有的狀態,從而從中尋找需要的答案。

2.狀態擴充套件方式。在廣度優先搜尋中,總是盡可能擴充套件狀態,並先擴充套件得出的狀態先進行下一次擴充套件。在解答樹上的變現為按層次遍歷所有狀態。

3.有效狀態。對有些狀態並不對其進行再一次擴充套件,而是直接捨棄它。因為根據問題分析可知,目標狀態不會由這些狀態經過若干次擴充套件得到。即目標狀態,不可能存在其在解答樹上的子樹上,所以直接捨棄。

4.佇列。為了實現先得出的狀態先進行擴充套件,使用佇列,將得到的狀態依次放入隊尾,每次取隊頭元素進行擴充套件。

5.標記。為了判斷哪些狀態是有效的,哪些是無效的往往使用標記。

6.有效狀態數。問題中的有效狀態數與演算法的時間複雜度同數量級,所以在進行搜尋之前必須估算其是否在所可以接受的範圍內。

7.最優。廣度優先搜尋常被用來解決最優值問題,因為其搜尋到的狀態總是按照某個關鍵字遞增(如前例中的時間和倒杯子次數),這個特性非常適合求解最優值問題。所以一旦問題**現最少、最短、最優等關鍵字,就要考慮是否是廣度優先搜尋。

1017 非常可樂

problem description 大家一定覺的運動以後喝可樂是一件很愜意的事情,但是seeyou卻不這麼認為。因為每次當seeyou買了可樂以後,阿牛就要求和seeyou一起分享這一瓶可樂,而且一定要喝的和seeyou一樣多。但seeyou的手中只有兩個杯子,它們的容量分別是n 毫公升和m 毫...

1017 非常可樂

題意 要求將一瓶可樂平均分成份,問能否平均分成兩份,如果能輸出最少需要幾次否則輸出no題目給出三個整數 s n m s表示可樂總量 n m分別為兩個杯子的容量 且 s n m 思路 先將m,n按大小排序 小的設為m 由 s 0 0 狀態 轉換到 0 s 2 s 2 的狀態且要找出最優解,用bfs 題...

1017 非常可樂

1017 非常可樂 題意 有體積為s的一瓶可樂,和體積為m,n的兩個杯子,他們都沒有刻度,求將可樂平分最少倒多少次。思路 三個杯子倒可樂,共有六種情況,s n,s m,m s,m n,n s,n m,判斷每種可能的情況,新增到佇列中,逐一搜尋。感想 直接對所有可能的情況搜尋,思路並不複雜。inclu...