分紅酒 藍橋杯 已更新

2021-06-21 02:05:28 字數 3043 閱讀 8238

這是2023年藍橋杯全國軟體大賽模擬題的第4題,問題是分紅酒,方法是bfs。

這是乙個關於廣度優先搜尋(bfs)的題目。每個杯中水的量只能為整數,所以狀態是有限的,遍歷這些狀態,並找出距離初始狀態最短的路徑,即為所求解。

廣度優先搜尋(bfs)使用佇列實現,正如深度優先搜尋(dfs)使用堆疊實現。

解題思路確定了,**實現就簡單一點了,當然也會出現小錯誤。

陣列模擬佇列

佇列是一種常用的先進先出(fifo)的資料結構,常用陣列模擬實現。

#include #include #include #include using namespace std;

typedef struct node node;

int vis[10][10][10];

int count = 0;

int a, b, c, d;

void bfs(void) ;

state.v[0] = 9;

state.v[1] = state.v[2] = state.v[3] = 0;

state.dist = 0;

q[front] = state;

vis[state.v[1]][state.v[2]][state.v[3]] = 1;

while(rear > front)

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

// i to j

node & news = q[rear];

memcpy(&news, &olds, sizeof(node));

int amount = min(olds.v[i], cap[j] - olds.v[j]);

news.v[i] -= amount;

news.v[j] += amount;

news.dist++;

if(!vis[news.v[1]][news.v[2]][news.v[3]])

}} front++;

} cout << "-1" << endl;

}int main(void)

stl佇列實現

c++ stl標準模板庫極大的提高了程式設計效率,雖然有時不如陣列靈活,解答這個問題還是沒問題的。

#include #include #include #include using namespace std;

typedef struct node node;

int vis[10][10][10];

int count = 0;

int a, b, c, d;

void bfs(void) ;

state.v[0] = 9;

state.v[1] = state.v[2] = state.v[3] = 0;

state.dist = 0;

q.push(state);

vis[state.v[1]][state.v[2]][state.v[3]] = 1;

while(!q.empty())

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

// i to j

node news;

memcpy(&news, &olds, sizeof(node));

int amount = min(olds.v[i], cap[j] - olds.v[j]);

news.v[i] -= amount;

news.v[j] += amount;

news.dist++;

if(!vis[news.v[1]][news.v[2]][news.v[3]])

}} }

cout << "-1" << endl;

}int main(void)

反例分析

解決這個問題的過程也是曲折的,剛開始的時候想使用stl中以整型指標為模板的queue,但是發現佇列中每次壓入的指標值都是相同的,把這個反例也分享一下吧。

#include #include #include #include using namespace std;

int vis[10][10][10];

int count = 0;

int a, b, c, d;

void bfs(void) ;

state[0] = 9;

state[1] = state[2] = state[3] = 0;

state[4] = 0;

q.push(state);

vis[state[1]][state[2]][state[3]] = 1;

while(!q.empty())

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

// i to j

int newstate[5];

memcpy(newstate, oldstate, sizeof(oldstate));

int quantity = min(oldstate[i], capacity[j] - oldstate[j]);

newstate[i] = oldstate[i] - quantity;

newstate[j] = oldstate[j] + quantity;

cout << newstate[0] << ", "

<< newstate[1] << ", "

<< newstate[2] << ", "

<< newstate[3] << ", "

<< newstate[4] << endl;

if(!vis[newstate[1]][newstate[2]][newstate[3]])

}} }

cout << "-1" << endl;

}int main(void)

這個反例,在我的電腦上每次壓入佇列的值均為0x28fe50,這是由於變數有效期的問題。

雖然文中提供了多種解決方案,但核心思想都是廣度優先搜尋(bfs)。

當然這個問題也可以擴充套件一下,把每個步驟的狀態列印出來。

(全文完)

藍橋杯 分紅酒

分紅酒 有4個紅酒瓶子,它們的容量分別是 9公升,7公升,4公升,2公升 開始的狀態是 9,0,0,0 也就是說 第乙個瓶子滿著,其它的都空著。允許把酒從乙個瓶子倒入另乙個瓶子,但只能把乙個瓶子倒滿或把乙個瓶子倒空,不能有中間狀態。這樣的一次倒酒動作稱為1次操作。假設瓶子的容量和初始狀態不變,對於給...

藍橋杯 BASIC題 (持續更新)

basic 13 基礎練習 數列排序 問題描述 給定乙個長度為n的數列,將這個數列按從小到大的順序排列。1 n 200 輸入格式 第一行為乙個整數n。第二行包含n個整數,為待排序的數,每個整數的絕對值小於10000。輸出格式 輸出一行,按從小到大的順序輸出排序後的數列。樣例輸入5 8 3 6 4 9...

藍橋杯 操作格仔(單點更新)

演算法訓練 操作格仔 時間限制 1.0s 記憶體限制 256.0mb 問題描述 有n個格仔,從左到右放成一排,編號為1 n。共有m次操作,有3種操作型別 1.修改乙個格仔的權值,2.求連續一段格仔權值和,3.求連續一段格仔的最大值。對於每個2 3操作輸出你所求出的結果。輸入格式 第一行2個整數n,m...