hdu1864 搜索版本

這道題目使用dp還要乘以100轉化爲0-1揹包問題,使用搜索版本更容易上手一點,終於體會到減枝的魅力,在深度遞歸中如果只像畢業bg那道那樣不取當前節點的展開不施加任何條件的話會超時(那道因爲取的路徑限制很嚴,而不像這裏是一個固定值,那裏可能也可以像這樣優化吧,覺得沒用,要根據具體數據關係特徵選擇減枝方案),而添加一個當前積累的money值加上除去當前結點之外的剩餘值之和能否超過目前得到的最大報銷額,沒有的話這個節點就不再展開,直接回溯;添加這個條件的話耗時 0ms 天啦 天壤之別,其實也容易理解 :最大報銷值的限制只適用於
該值較小的情況讓其很早回溯,但當該值很大情況就收效甚微(極端情況是大於所有發票額的綜合,整棵樹遍歷 一個測試用例可達2的30次方)這個限制然是針對取當前值而用的  我們還可以對不取當前值增加一個限制 就是去掉當前結點所剩額能超過目前得到的最大值,這樣對 限額比較大時特別有用(原來以爲從大到小排列性能會更高,經測試都一樣) 兩者共同使其達到平衡;

 

 ps:浙大的題目老師設置一些細微的細節作爲陷阱,以後要小心 認真讀題目的條件,一般沒有什麼信息是多餘的,開始忽視了相同編號的好幾項之和不能超過600 幾項分離並不是沒有意義的,開始審題忽視了這個信息出問題修改很難發現,以後對此類信息要提高敏感度

 

 

#include<iostream>
#include<algorithm>
#include <iomanip>
using namespace std;

double price[32];
int top;
double maxget;
double maxcost;

void dfs(int i,int n,double nowcost,double remain)//maxcost不變作爲全局變量
{
 if(i>n)
 {
  if(nowcost>maxget)maxget=nowcost;return;
 }
 if(nowcost+remain-price[i]>maxget)//減枝的妙用,其實兩個是串通的 儘早放棄不再往深處延伸
  dfs(i+1,n,nowcost,remain-price[i]);//不計當前發票
 if(nowcost+price[i]<=maxcost/*&&nowcost+remain>maxget*/)//覺得這個條件沒用,是靠不取減枝,兩頭夾
  dfs(i+1,n,nowcost+price[i],remain-price[i]);//包括當前發票
}
int cmp(double x,double y)
{
 return x<y;
}
int main()
{
 int n;
 while(cin>>maxcost>>n&&n)
 {
  top=-1;
  while(n--)
  {
   double cost=0;
   double arr[3]={0};
   int tag=1;
   int m;
   cin>>m;

   char type,c;
   double in;
   while(m--)
   {
    cin>>type>>c>>in;
    if(in>600||(type!='A'&&type!='B'&&type!='C'))tag=0;//don't break;
    if(type=='A')arr[0]+=in;
    if(type=='B')arr[1]+=in;
    if(type=='C')arr[2]+=in;
    cost+=in;
   }
   if(cost>1000)tag=0;
   if(arr[0]>600||arr[1]>600||arr[2]>600)tag=0;
   if(cost>maxcost)tag=0;//減枝,不在遞歸裏意義不大
   if(tag)price[++top]=cost;
  }
  sort(price,price+top+1,cmp);
  maxget=0;
  double remain=0;
  for(int t=0;t<=top;t++)remain+=price[t];

  dfs(0,top,0,remain);
  cout<<setiosflags(ios::fixed)<<setprecision(2)<<maxget<<endl;
 }
 return 0;
}

發佈了39 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章