題目鏈結
problem description
大家一定覺的運動以後喝可樂是一件很愜意的事情,但是seeyou卻不這麼認為。因為每次當seeyou買了可樂以後,阿牛就要求和seeyou一起分享這一瓶可樂,而且一定要喝的和seeyou一樣多。但seeyou的手中只有兩個杯子,它們的容量分別是n 毫公升和m 毫公升 可樂的體積為s (s<101)毫公升 (正好裝滿一瓶) ,它們三個之間可以相互倒可樂 (都是沒有刻度的,且 s==n+m,101>s>0,n>0,m>0) 。聰明的acmer你們說他們能平分嗎?如果能請輸出倒可樂的最少的次數,如果不能輸出"no"。input
三個整數 : s 可樂的體積 , n 和 m是兩個杯子的容量,以"0 0 0"結束。output
如果能平分的話請輸出最少要倒的次數,否則輸出"no"。sample input
7 4 3sample output4 1 3
0 0 0
no樣例的輸出結果解析:3
設s是瓶子(我看做大杯子),a、b兩個杯子
s=4a=1
b=3400
1031
1220
2所以三次的騰挪,可以讓s中的可樂平分
雖然知道這個是bfs題,但是僅僅對dfs有一點了解的情況下,實在是不清楚怎麼做的,既然是廣度搜尋,那如何記錄深度呢?要知道dfs可是用引數記錄的
經過學長講解,可以用佇列的先進先出的性質結合結構體來做dfs
第一步,根據題意建立結構體和jud陣列:
typedef
struct
h;
剛聽完自己做的時候只定義了s、a、b。。。最精髓的t沒有定義,導致走了不少彎路
我們可以把三個杯子每種可能的容量叫做狀態,就是說,最開始的狀態就是
瓶子容量等於s,兩個小杯子為0,我們需要按照資料規模開個鄉音的bool陣列防止兩個杯子之間反覆倒來倒去的存在(其實不一定是兩個杯子倒來倒去,有可能有其他組合也能組成永動不停的情況,舉個最簡單的例子利於以後的自己理解。)
**理解:
//操作
if(操作後形成的狀態以前沒有)
第二步:規定邊界,這題邊界很好想:就是存在兩個杯子的容量相同//操作前:s代表總量,當前s代表的是當前大杯子容納的
if((當前s==當前a )&& 當前s==s/
2||當前b==當前a && 當前b==s/
2||當前s==當前b && 當前s==s/2)
//停止廣搜
第三步:思考什麼規定成全域性變數:
很顯然,三個杯子的總容量和可樂總量比較適合作為全域性變數(因為狀態合不合理需要靠這三個量評判,不能出現乙個杯子裝不下的情況出現,這段話作為下面的剪枝環節的鋪墊)
第四步:把初始狀態裝入佇列頭中去
這一步可以當做bfs的初始化來做。
然後就是考慮bfs的思考規律
dfs就是遞迴到底,直到沒法遞迴才返回上一層,而bfs需要把一層的每個點都走一遍,一開始真的搞不懂該怎麼做,stl的理解還是太淺既然用了佇列+結構體成員表示層數,就不在需要用遞迴的引數去表示層數了
那麼。。bfs的引數到底代表啥?
int
main()
bfs(s,a,b)
;//把邊界傳進去
while
(!q.
empty()
) jud =
false
;//全域性的jud,是否找到邊界狀態的標誌,總不能引數帶乙個jud把,顯得bfs的定義太臃腫了
memset
(jud,0,
sizeof
(jud));
//清零
}}
dfs是遞迴,bfs是迴圈
bfs的注意點:
1、佇列定義成全域性的!
2、用初狀態初始化佇列!
、#include
#include
#include
using
namespace std;
typedef
long
long ll;
bool jud[
101]
[101][
101]
;inline ll read()
inline
void
out(ll a)
typedef
struct
h;h h1, h2;
//乙個是存起始狀態的,乙個是動態的
int time;
bool jud;
queueq;
//佇列
void
bfs(
int s,
int a,
int b)
//s->a
if(h1.s)
else
h2.b = h1.b;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//s->b,上面的複製過來,a變成b,b變成a就行了
if(h1.s)
else
h2.a = h1.a;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//a->b
//a->s
//b->a
//b->s}if
(jud)
else
cout <<
"no"
<< endl;
}int
main()
bfs(s,a,b)
;while
(!q.
empty()
) jud =
false
;//全域性的jud,是否找到邊界狀態的標誌,總不能引數帶乙個jud把,顯得bfs的定義太臃腫了
memset
(jud,0,
sizeof
(jud));
//清零
}}
通過本題總結一些bfs的特點:
1、用引數做邊界
2、用while代替遞迴,這也是它跟dfs的乙個區別
3、bfs大致可分解成
思路有點亂,等待後續完善
#include
#include
#include
using
namespace std;
typedef
long
long ll;
bool jud[
101]
[101][
101]
;inline ll read()
inline
void
out(ll a)
typedef
struct
h;h h1, h2;
//乙個是存起始狀態的,乙個是動態的
int time;
bool jud;
queueq;
//佇列
void
bfs(
int s,
int a,
int b)
//s->a
if(h1.s)
else
h2.b = h1.b;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//s->b,上面的複製過來,a變成b,b變成a就行了
if(h1.s)
else
h2.a = h1.a;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//a->b
if(h1.a)
else
h2.s = h1.s;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//a->s
if(h1.a)
else
h2.b = h1.b;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//b->a
if(h1.b)
else
h2.s = h1.s;if(
!jud[h2.s]
[h2.a]
[h2.b])}
//b->s
if(h1.b)
else
h2.a = h1.a;if(
!jud[h2.s]
[h2.a]
[h2.b])}
}if(jud)
else
cout <<
"no"
<< endl;
}int
main()
bfs(s,a,b)
;while
(!q.
empty()
) jud =
false
;//全域性的jud,是否找到邊界狀態的標誌,總不能引數帶乙個jud把,顯得bfs的定義太臃腫了
memset
(jud,0,
sizeof
(jud));
//清零
}}
hdu 1495 非常可樂
題意 給你三個容器讓你平分可樂,求最少的步數。思路 一看到求最少步數,就想到了廣搜,但是沒有思路,但看別人分情況,瞬間就明白啦。可以s n,s m,n s,n m,m s,m n這六種情況討論就行,每種又有倒完和倒不完兩種情況,直到出現兩個容器都有s 2,這就是最少步數。但s是奇數時是不能平分的,三...
hdu 1495 非常可樂
hdu 1495 非常可樂 題目大意 給你三個容器,他們的容量分別是 s,n,m 且s n m,給你s,n,m。s代表裝在容器裡可樂,n和m代表的是兩個杯子的容量,求他們能否平分這杯可樂。如果能就輸出倒的最小次數,如果不能就輸出 no。題目分析 也就是要達到能 s 2,0,s 2或 0 s 2,s ...
hdu 1495 非常可樂
兩個杯子按大小排序,為s m n,1.只要n滿了,就把n裡的東西放到s中 2.只要m非空,就把m中的放到n中 3.如果m為空,把s中的放到m中 超時 include int n,m,s int main if ss aa bb 0 得到均分 if bb b 若小杯子裡裝滿可樂,將小杯子裡的可樂倒入可...