天梯賽L3 001 湊零錢 (01揹包 dfs)

2021-09-10 16:46:55 字數 2024 閱讀 1161

l3-001 湊零錢 (30 分)

輸入第一行給出兩個正整數:n(≤10​4​​)是硬幣的總個數,m(≤10​2​​)是韓梅梅要付的款額。第二行給出 n 枚硬幣的正整數面值。數字間以空格分隔。

在一行中輸出硬幣的面值 v​1​​≤v​2​​≤⋯≤v​k​​,滿足條件 v​1​​+v​2​​+...+v​k​​=m。數字間以 1 個空格分隔,行首尾不得有多餘空格。若解不唯一,則輸出最小序列。若無解,則輸出no solution

注:我們說序列比「小」,是指存在 k≥1 使得 a[i]=b[i] 對所有 i解題思路 

由於要輸出最小序列,所以先給陣列v排序。

本題的01揹包中,dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]] + v[i])。也就是說dp[i][j]的值是由dp[i-1][j]和dp[i-1][j-v[i]] + v[i]中的較大者決定的,當兩者相同時,就會產生多解。反過來說,dp[i][j]可能會決定dp[i+1][j]或者dp[i+1][j+v[i+1]]。用乙個二維陣列way[i][j](初始化為0)來儲存dp[i][j]所決定的物件(1為dp[i+1][j],2為dp[i+1][j+v[i+1]],3為兩者都能決定)。然後就把路徑記錄好了,可以用來搜尋了。

如果dp[n][m]小於m說明沒有方案可以湊到,就直接輸出"no solution"。

否則,因為要求輸出最小序列,所以要從小到大試過去。開乙個迴圈i從0到n-1,每次從(i, 0)開始dfs,因為dp[i+1][v[i+1]]都是由dp[i][0]決定的(就是第乙個放入揹包的要從小到大嘗試)。然後用乙個stack儲存答案,如果找到了等於m的點,就返回true,當dp[i][j]可以決定dp[i+1][j+v[i+1]]的時候(選擇v[i+1]加入揹包),在返回true前把v[i+1]入棧。如果沒有路了(way[i][j] == 0),就返回false。(這段說的有點亂,看**吧)

還有一點需要注意,當way[i][j]==3的時候,要先dfs (i+1,j+v[i+1])再dfs(i+1,j)。因為前者把v[i+1]放入揹包,後者沒有,那就會放入乙個比v[i+1]大的。

dfs**如下

bool dfs(int x, int y, stack& sta)

} else if(way[x][y] == 2)

} else if(way[x][y] == 3)

if(dfs(x + 1, y, sta))

return true;

} return false;

}

完整**如下

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

int dp[10005][105];

int v[10005];

int way[10005][105]; //1,x+1,y 2,x+1,y+v[x+1] 3,1and2

int n, m;

bool dfs(int x, int y, stack& sta)

} else if(way[x][y] == 2)

} else if(way[x][y] == 3)

if(dfs(x + 1, y, sta))

return true;

} return false;

}int main()

else //已經決定了一種

way[i - 1][j] = 3;

}

else

if(dp[i - 1][j] <= dp[i - 1][j - v[i] + v[i]])

}

}}

if(dp[n][m] != m)

cout << "no solution" << endl;

else

cout << endl;

break;

}}

} }return 0;

}

L3 001 湊零錢 (01揹包)

時間限制 200 ms 記憶體限制 65536 kb 長度限制 8000 b 判題程式 standard 作者 陳越 輸入格式 輸入第一行給出兩個正整數 n 104 是硬幣的總個數,m 102 是韓梅梅要付的款額。第二行給出n枚硬幣的正整數面值。數字間以空格分隔。輸出格式 在一行中輸出硬幣的面值 v...

L3 001 湊零錢 dp 滿01揹包

時間限制 200 ms 記憶體限制 65536 kb 長度限制 8000 b 判題程式 standard 作者 陳越 輸入格式 輸入第一行給出兩個正整數 n 104 是硬幣的總個數,m 102 是韓梅梅要付的款額。第二行給出n枚硬幣的正整數面值。數字間以空格分隔。輸出格式 在一行中輸出硬幣的面值 v...

L3 001 湊零錢(dfs或者01揹包)

時間限制 200 ms 記憶體限制 65536 kb 長度限制 8000 b 判題程式 standard 作者 陳越 輸入格式 輸入第一行給出兩個正整數 n 104 是硬幣的總個數,m 102 是韓梅梅要付的款額。第二行給出n枚硬幣的正整數面值。數字間以空格分隔。輸出格式 在一行中輸出硬幣的面值 v...