1. 程式人生 > 實用技巧 >洛谷 P1048 採藥 (啟發式搜尋)

洛谷 P1048 採藥 (啟發式搜尋)

題面

題目描述
辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了一個難題。醫師把他帶到一個到處都是草藥的山洞裡對他說:“孩子,這個山洞裡有一些不同的草藥,採每一株都需要一些時間,每一株也有它自身的價值。我會給你一段時間,在這段時間裡,你可以採到一些草藥。如果你是一個聰明的孩子,你應該可以讓採到的草藥的總價值最大。”

如果你是辰辰,你能完成這個任務嗎?

輸入格式
第一行有 22 個整數 TT(1 \le T \le 10001≤T≤1000)和 MM(1 \le M \le 1001≤M≤100),用一個空格隔開,TT 代表總共能夠用來採藥的時間,MM 代表山洞裡的草藥的數目。

接下來的 MM 行每行包括兩個在 11 到 100100 之間(包括 11 和 100100)的整數,分別表示採摘某株草藥的時間和這株草藥的價值。

輸出格式
輸出在規定的時間內可以採到的草藥的最大總價值。

程式碼實現

很明顯的揹包吧。這裡我們寫一個啟發式搜尋,所謂的啟發式搜尋,就是我們在搜尋的時候用一個估價函式去幫助和優化我們的決策。當我們選擇一樣草藥的時候沒什麼好說的,直接往下搜,當我們不選的時間,我們有估價函式來幫助我們判斷,接下來的價值是否大於我們目前的最優值,如果不大於那麼顯然我們沒有必要進行下一輪的搜尋。你可以理解為這個估價函式是幫助我們剪枝的一個工具。

程式碼實現

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
int n,m,ans;
const int maxn=105;
struct node {
    int a,b;
    double val;
}e[maxn];

bool cmp (node a,node b) {
    return a.val>b.val;
}

int f(int t,int v) {
   int tot=0;
   for (int i=0;i+t<=n;i++) {
       if (v>=e[t+i].a) {
           v-=e[i+t].a;
           tot+=e[i+t].b;
       }
       else return (int ) (tot+v*e[i+t].val);
   }
   return tot;
}

void dfs (int t,int pass,int v) {

   ans=max (ans,v);
   if (t>n) return ;
   if (f(t,pass)+v>=ans) dfs (t+1,pass,v);
   if (e[t].b<pass) dfs (t+1,pass-e[t].a,v+e[t].b);

}

int main () {
    cin>>m>>n;
    for (int i=1;i<=n;i++) {
        cin>>e[i].a>>e[i].b;
        e[i].val=1.0*e[i].b/e[i].a;
    }   
    sort (e+1,e+1+n,cmp);
    dfs (1,m,0);
    cout<<ans<<endl;
    
    return 0;
}