這是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...