P2744 「USACO5.3」量取牛奶 Milk Measuring
阿新 • • 發佈:2022-12-13
將桶按容積大小從小到大排序,令 \(f_{i,j}\) 表示前 \(i\) 個桶能否量出 \(j\) 夸脫,如果可以就用 vector
儲存最優方案。
先列舉桶的種類再列舉夸脫數,轉移看似只有兩種:之前有或沒有用過 \(i\) 號桶,新用一次 \(i\) 號桶。但這樣是錯誤的,可能存在中間狀態最優解長度較長的情況。具體例子可以看程式碼末尾。
所以我們還需要額外列舉用桶的次數而不是一次一次用,這樣最優情況就不會被覆蓋了。時間複雜度 \(O(Q^2\log P)\)。
考慮將桶按容積從大到小排序,令 \(f_{i,j}\) 表示前 \(i\) 個桶能否量出 \(j\) 夸脫,如果可以就令 \(g_{i,j}\)
這樣我們就可以一次一次用了,最優解肯定不會被覆蓋。
最後再根據記錄的資訊搜尋一遍,\(\require{cancel}\require{enclose}\sout{O(kQ^2P\log P)}\) 跑得飛快,其中 \(k\) 取決於方案長度,很小很小。
#include<bits/stdc++.h> using namespace std; #define N 105 #define NN 20005 #define For(i,x,y)for(i=x;i<=(y);i++) #define Down(i,x,y)for(i=x;i>=(y);i--) int g[N][NN],c[N]; /*vector<int>h[N][NN];*/ bool used[N][NN],f[N][NN]; vector<int>print(int now,int pos) { if(g[pos][now]==1)return{c[pos]}; /*if(!h[pos][now].empty())return h[pos][now];*/ int i,j,k; vector<int>vec,tmp; Down(i,pos-1,1) { j=now; while(j>=c[pos]) { j-=c[pos]; /*cerr<<i<<' '<<j<<' '<<pos<<' '<<now<<' '<<g[i][j]<<' '<<g[pos][now]<<endl;*/ if(used[i][j]&&g[i][j]+1==g[pos][now]) { tmp=print(j,i); if(vec.empty())vec=tmp; else { Down(k,vec.size()-1,0) if(vec[k]!=tmp[k])break; if(~k&&vec[k]>tmp[k])vec=tmp; } } } if(!vec.empty()) { vec.push_back(c[pos]); /*h[pos][now]=vec;*/ return vec; } } } int main() { int Q,p,i,j; vector<int>vec; cin>>Q>>p; For(i,1,p)cin>>c[i]; sort(c+1,c+p+1,greater<int>()); f[0][0]=1; For(i,1,p) For(j,0,Q) if(j<c[i]) { f[i][j]=f[i-1][j]; g[i][j]=g[i-1][j]; used[i][j]=0; } else { if(!f[i-1][j]&&!f[i][j-c[i]])continue; if(!f[i-1][j]||f[i-1][j]&&f[i][j-c[i]]&&g[i][j-c[i]]+1-used[i][j-c[i]]<=g[i-1][j])f[i][j]=used[i][j]=1,g[i][j]=g[i][j-c[i]]+1-used[i][j-c[i]]; else { f[i][j]=1; used[i][j]=0; g[i][j]=g[i-1][j]; } } cout<<g[p][Q]<<' '; Down(i,p,1) if(used[i][Q])break; vec=print(Q,i); Down(i,vec.size()-1,0)cout<<vec[i]<<' '; return 0; } //#include<bits/stdc++.h> //using namespace std; //#define N 105 //#define NN 20005 //#define For(i,x,y)for(i=x;i<=(y);i++) //int c[N]; //bool f[N][NN]; //vector<int>vec[N][NN]; //bool pd(vector<int>&x,vector<int>&y) //{ // return x.size()<y.size()||x.size()==y.size()&&x<y; //} //int main() //{ // bool bo; // int Q,p,i,j,k; // cin>>Q>>p; // For(i,1,p)cin>>c[i]; // sort(c+1,c+p+1); // f[0][0]=1; // For(i,1,p) // For(j,0,Q) // { // f[i][j]=f[i-1][j]; // vec[i][j]=vec[i-1][j]; // For(k,1,j/c[i]) // if(f[i-1][j-c[i]*k]) // { // vec[i-1][j-c[i]*k].push_back(c[i]); // if(!f[i][j]||pd(vec[i-1][j-c[i]*k],vec[i][j]))f[i][j]=1,vec[i][j]=vec[i-1][j-c[i]*k]; // vec[i-1][j-c[i]*k].pop_back(); // } // /*if(j>=c[i]&&f[i-1][j-c[i]]) // { // vec[i-1][j-c[i]].push_back(c[i]); // if(!f[i][j]||pd(vec[i-1][j-c[i]],vec[i][j]))f[i][j]=1,vec[i][j]=vec[i-1][j-c[i]]; // vec[i-1][j-c[i]].pop_back(); // } // if(j>=c[i]&&f[i][j-c[i]]) // { // bo=0; // if(vec[i][j-c[i]].empty()||vec[i][j-c[i]].back()<c[i])bo=1,vec[i][j-c[i]].push_back(c[i]); // if(!f[i][j]||pd(vec[i][j-c[i]],vec[i][j]))f[i][j]=1,vec[i][j]=vec[i][j-c[i]]; // if(bo)vec[i][j-c[i]].pop_back(); // } // if(i==1&&j==3)cerr<<vec[i][j].size()<<endl;*/ // } // /*p=3; // Q=7247+949*1; // cerr<<f[p][Q]<<' ';*/ // cout<<vec[p][Q].size(); // For(i,0,int(vec[p][Q].size())-1)cout<<' '<<vec[p][Q][i]; // return 0; //} /* 16737 4 904 909 916 949 */