洛谷P1411 砝碼稱重
阿新 • • 發佈:2018-10-29
false http 時間 .org 背包 ret code 就是 傳送門
傳送門啦
這個題總體思路就是先搜索在 $ dp $
void dfs(int keep,int now){ //使用 放棄 if(now > m) return; //已經放棄超過m個了,就退出 if(keep == n){ if(now == m) dp(); return ; } ///如果搜索完後正好符合條件,執行一次dp過程 dfs(keep + 1 , now); //這個砝碼選 vis[keep] = true;//打標記 dfs(keep + 1 , now + 1); //這個砝碼放棄 vis[keep] = false;//取消標記 }
觀察題目可得,這個過程可以通過01背包實現。
定義 $ f[i][j] $ 為當前選取到了第j個砝碼,如果通過之前的砝碼可以稱量出重量 $ i $ 那麽 $ f[i][j] $ 的值為 $ true $ 。
狀態轉移方程為: $ f[i][j]=f[i-a[i]][j-1] $
初始狀態為 $ f[0][j]=true $
最後 $ f[i][n] $ 中 $ true $ 的個數就是通過這些砝碼可以計算出的重量值。通過一維數組,我們可以只定義一個 $ f[i] $ 數組,降低了時間復雜度,註意此時內層循環倒序。
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> using namespace std; inline int read(){ char ch = getchar(); int f = 1 , x = 0; while(ch > '9' || ch < '0'){if(ch == '-')f = -1;ch = getchar();} while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();} return x * f; } int n,m,a[300]; bool vis[300]; int ans,f[3000],tot,res; void dp(){ memset(f , 0 , sizeof(f)); f[0] = true; ans = tot = 0; for(int i=0;i<n;i++){ if(vis[i]) continue; for(int j=tot;j>=0;j--) if(f[j] && !f[j+a[i]]){ f[j+a[i]] = true; ans++; } tot += a[i]; } res = max(ans , res); } void dfs(int keep,int now){ //使用 放棄 if(now > m) return; if(keep == n){ if(now == m) dp(); return ; } dfs(keep + 1 , now); vis[keep] = true; dfs(keep + 1 , now + 1); vis[keep] = false; } int main(){ n = read(); m = read(); for(int i=0;i<n;i++) { a[i] = read(); } dfs(0 , 0); printf("%d\n",res); return 0; }
洛谷P1411 砝碼稱重