?? usaco_4_1_2_fence8.cpp
字號:
/*
TASK: fence8
LANG: C++
*/
/*
這道題真是相當惡心……
提交9次后終于過了,剛開始時的第4組數據~~o(∩_∩)o...哈哈,終于A掉了!
題目求能切出來的最多木料,而且木料不管長短,價值都是1,這樣的多重背包看起來簡單,遺憾的是50個包挑1023個東西,而且包的容量各不相同。
只能搜索。這里用到了以前沒用到過的搜索方法,DFSID(Depth First with Iterative Deepening)
usaco在1.4的時候有提到過這種搜索方法,事實上就是當BFS空間不夠時的一種用時間向空間妥協的方法。
迭代加深搜索的時間復雜度高于廣搜,usaco的分析如下:
Depth First with Iterative Deepening (ID)
An alternative to breadth first search is iterative deepening. Instead of a single breadth first search, run D depth first searches in succession, each search allowed to go one row deeper than the previous one. That is, the first search is allowed only to explore to row 1, the second to row 2, and so on. This ``simulates'' a breadth first search at a cost in time but a savings in space.
Complexity
The space complexity of iterative deepening is just the space complexity of depth first search: O(n). The time complexity, on the other hand, is more complex. Each truncated depth first search stopped at depth k takes ck time. Then if d is the maximum number of decisions, depth first iterative deepening takes c0 + c1 + c2 + ... + cd time.
If c = 2, then this sum is cd+1 - 1, about twice the time that breadth first search would have taken. When c is more than two (i.e., when there are many choices for each decision), the sum is even less: iterative deepening cannot take more than twice the time that breadth first search would have taken, assuming there are always at least two choices for each decision.
另外就是剪枝:
1.這道題由于木料的價值都是1,所以必然如果最大能切K個,則這K個木料必定是木料從小到大排序后的前K個。先把后面的那些剪掉 。
2.在分析搜索樹時,搜索樹越扁平,那么同樣的剪枝效率越低,搜索樹跟部越窄,剪枝效果越明顯。所以我們把木料從大到小搜索,而木板從小到大搜索。
3.由于有重復的木料出現,那么在搜索的過程中,如果rail[i]==rail[i-1],而第i塊木料在第K塊木板上切的,那么第i-1塊木料必定在大于等于K的木板上切出。這個方法可以剪掉很多!!
4.對于切剩下的board(無法再切下rail),統計一下總和。如果大于 board長度總和-rail長度總和,一定無解,可以剪枝。
*/
#include<iostream>
#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin("fence8.in");
ofstream fout("fence8.out");
int nbd,nrail,best;
int board[51];
int rail[1024];
int rem[51];
int sumlen[1024];
long long sum=0;
long long maywaste,waste;
void DFS(int depth,int index)
{
if(depth == 0)
{
for(int i=index; i<nbd; ++i)
if (rem[i]>=rail[0])
{
fout << best+1 << endl;
fout.close();
exit(0);
}
return;
}
for(int i=index; i<nbd; ++i)
if(rem[i]>=rail[depth])
{
long long oldwaste=waste;
rem[i]-=rail[depth];
if (rem[i]<rail[0] && waste+rem[i]>maywaste) //剪枝方法4
{
rem[i]+=rail[depth];
continue;
}
if (rem[i]<rail[0]) waste+=rem[i];
if(rail[depth-1] == rail[depth]) DFS(depth-1,i); //剪枝方法3
else DFS(depth-1,0);
rem[i]+=rail[depth];
waste=oldwaste;
}
}
void DFSID(int nr)
{
for(int i=nr-1;i>=0;--i){ //木料從大到小
waste=0;
maywaste=sum-sumlen[i]; //記錄木板的總長比木料總長多的值
best=i;
DFS(i,0);
}
}
int main()
{
fin>>nbd;
for(int i=0;i<nbd;i++){
fin>>board[i];
sum+=board[i];
rem[i]=board[i];
}
fin>>nrail;
for(int i=0;i<nrail;i++)
fin>>rail[i];
fin.close();
sort(board,board+nbd); //剪枝方法2的排序
sort(rail,rail+nrail);
int temp=0;
sumlen[0]=rail[0];
while(temp<nrail && sumlen[temp]<=sum){ //剪枝方法1
++temp;
sumlen[temp]=sumlen[temp-1]+rail[temp];
}
nrail=temp;
DFSID(nrail);
fout<<'0'<<endl;
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -