題解 CF746D 【Green and Black Tea】

題目分析

這道題表面上看上去挺簡單,其實仔細研究一下還是值得鑽研的。我本人做這道題使用的任然是$ DFS01 $背包。不過呢,與往常背包不同的是,這次遞歸中需要加許多參數。就數據強度來看,棧問題不大。

遞歸過程

我們使用一個棧以及兩個臨時棧。每次在裡面$ push $當前的解。只有「G」與「B」。兩個棧分別處理和紅茶和和綠茶的情況。兩種情況都要考慮到已經連續喝了幾次某種茶。

在遞歸函數里,我們用到$ dep,s,g,h,last $ 這幾個變數。分別代表深度、連續喝的總數、綠茶喝的總數、紅茶喝的總數以及上次喝的茶是啥。$ 0 $代表綠茶,$1$代表紅茶。

遞歸程式碼:

void dfs(int dep,int s,int g,int h,bool last)
{
if(dep>n)
{
stack<string>temp1=temp;
while(!temp1.empty())
{
cout<<temp1.top();
temp1.pop();
}
exit(0);
}
else
{
if(last==0)
{
temp.push("G");
if(g+1<=a)dfs(dep+1,s,g+1,h,!last);
if(s+1<=b&&s<k) dfs(dep+1,s+1,g,h+1,last);
else
{
cout<<"NO"<<endl;
exit(0);
}
}
else
{
temp.push("B");
if(s+1<=b)dfs(dep+1,s,g,h+1,!last);
if(g+1<=a&&s<k) dfs(dep+1,s+1,g,h,last);
else
{
cout<<"NO"<<endl;
exit(0);
}
}
}
if(!temp.empty()) temp.pop();
}

主函數

最後主函數的程式就簡單了。像往常一樣,$ dep $總是要是$ 1 $開始,其他都是$ 0 $;但是有一個問題,我們不僅要考慮第一次喝綠茶的情況,第一次還可能是紅茶。所以我們在剛開始寫遞歸函數的時候,我們需要遞歸兩遍

主函數程式碼:

int main()
{
cin>>n>>k>>a>>b;
dfs(1,0,0,0,0);
dfs(1,0,0,0,1);
return 0;
}

完整程式碼

#include<bits/stdc++.h>
using namespace std;
int n,k,a,b;
stack<string>temp;
void dfs(int dep,int s,int g,int h,bool last)
{
if(dep>n)
{
stack<string>temp1=temp;
while(!temp1.empty())
{
cout<<temp1.top();
temp1.pop();
}
exit(0);
}
else
{
if(last==0)
{
temp.push("G");
if(g+1<=a)dfs(dep+1,s,g+1,h,!last);
if(s+1<=b&&s<k) dfs(dep+1,s+1,g,h+1,last);
else
{
cout<<"NO"<<endl;
exit(0);
}
}
else
{
temp.push("B");
if(s+1<=b)dfs(dep+1,s,g,h+1,!last);
if(g+1<=a&&s<k) dfs(dep+1,s+1,g,h,last);
else
{
cout<<"NO"<<endl;
exit(0);
}
}
}
if(!temp.empty()) temp.pop();
}
int main()
{
cin>>n>>k>>a>>b;
dfs(1,0,0,0,0);
dfs(1,0,0,0,1);
return 0;
}