zoukankan      html  css  js  c++  java
  • 【9.14NOIP模拟pj】wtaxi 题解——搜索

    【9.14NOIP模拟pj】wtaxi

    题目简化

    有K辆车,N个人,上车给D元,只有S分钟。上车后无论多少人都要给D元,原地等多少分钟就没了多少元。求最小花费的钱。


    我的思路

    毫无疑问,此题可以用搜索做,DFS和BFS都行。

    程序1

    设三个参数,分别为(第l辆车,共花了sum元,还剩下m人)。花的时间在后面加上,否则有点麻烦一点。
    两种情况:选或不选
    不选 l+1;
    选 l+1,已经花的钱+时间*上车人数+上车需要的钱(D),m-上车的人

    程序2

    我觉得,纯暴搜定然不过,所以加个记忆化。因为记忆化必须要在后面的操作一样时,才可以比较,取最优的。设bz[l,m]表示在第l辆车,剩m人时花的最少钱(sum)
    和sum比较即可

    程序3.1

    我担心第二代程序过不了,再加了一层优化。有时,剩下的人即使将剩下的车全坐满,仍然不够。所以判断m和剩下的座位之和的关系,若m比其还大,则退出,因为即使后面的坐满,仍不能全走。

    (未试过)程序3.2

    已经满的车无需考虑


    所以,此题可用**DFS+记忆化+剪枝**AC之

    程序实践3.1

    C++

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <climits>
    using namespace std;
    int n,k,d,s;                    
    int t[101],z[101];                  
    int bz[101][101],sm[102];//bz见上,sm[i]表示到i辆车时剩下的车最多能坐的人数(包括i)
    int ans=INT_MAX;
    int min_a_b(int a,int b)
    {
        if (a<b) return a;
        return b;
    }
    void go(int l,int sum,int m)
    {
        if (sum>bz[l][m]) return;
        bz[l][m]=sum;//记忆化操作,把大于之前的排除       
        if (sm[l]<m) return;//剪枝操作,把大于最大座位的人数排除
        if (m<=0) 
        {
            if (sum<ans) ans=sum;//替换ans
            return;
        }
        if (l>k) return;//车没了,人还在的情况
        go(l+1,sum+min_a_b(z[l],m)*t[l]+d,m-min_a_b(z[l],m));//选
        go(l+1,sum,m);//不选
        return;
    }
    int main()
    {
        freopen("wtaxi.in","r",stdin);
        freopen("wtaxi.out","w",stdout);
        int i,j;
        scanf("%d%d%d%d",&n,&k,&d,&s);
        for(i=1;i<=k;i++)
        {
            scanf("%d%d",&t[i],&z[i]);
        }
        for(sm[k+1]=0,i=k;i>0;i--)
        {
            sm[i]=sm[i+1]+z[i];//求剩下车中最大座位
        }
        memset(bz,127,sizeof(bz));//初始化
        go(1,0,n);
        if (ans==INT_MAX) 
        {
            printf("impossible
    ");
            return 0;
        }
        printf("%d
    ",ans);
        return 0;
    }

    Pascal

    var
            n,k,d,s:longint;
            i,j:longint;
            t,z:array[0..100]of longint;
            bz:array[0..100,0..100]of longint;//bz见上
            sm:array[0..101]of longint;//sm[i]表示到i辆车时剩下的车最多能坐的人数(包括i)
            ans:longint=maxlongint;
    function min(a,b:longint):longint;
    begin
            if a<b then exit(a);
            exit(b);
    end;
    procedure go(l,sum,m:longint);
    begin
            if sum>bz[l,m] then exit;
            bz[l,m]:=sum;//记忆化操作,把大于之前的排除   
            if sm[l]<m then exit;//剪枝操作,把大于最大座位的人数排除
            if m<=0 then
            begin
                    if sum<ans then ans:=sum;//替换ans
                    exit;
            end;
            if l>k then exit;//车没了,人还在的情况
            go(l+1,sum+min(z[l],m)*t[l]+d,m-min(z[l],m));//选
            go(l+1,sum,m);//不选
    end;
    begin
            assign(input,'wtaxi.in');reset(input);
            assign(output,'wtaxi.out');rewrite(output);
            readln(n,k,d,s);
            for i:=1 to k do readln(t[i],z[i]);
            sm[k+1]:=0;
            for i:=k downto 1 do sm[i]:=sm[i+1]+z[i];//求剩下车中最大座位
            fillchar(bz,sizeof(bz),127);//初始化
            go(1,0,n);
            if ans=maxlongint then
            begin
                    writeln('impossible');
                    close(input);
                    close(output);
                    halt;
            end;
            writeln(ans);
            close(input);
            close(output);
    end.

    总结

    1. 类似于这样的题可以用搜索做
    2. 记忆化可以加快程序速度,但要保证程序是正确的,只是删掉不必要的运算
      1.不一定要保证前面走过的路一样
      2.要保证后面的路一样,它们要在同一可以比较的点上,才能记忆化,取最优的
    3. 剪枝也可以删掉一些不必要的运算,但它是根据最不利原则,求出的一个范围,把范围外的去掉
  • 相关阅读:
    oracle11g静默安装
    pv vg lv
    oracle日志表
    oracle常用sql
    vulnhub~muzzybox
    vulnhub~sunset:dusk1
    vulnhub~MyExpense
    vulnhub~DC-9
    汇编学习一
    贪心算法和动态规划
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145324.html
Copyright © 2011-2022 走看看