zoukankan      html  css  js  c++  java
  • 初涉状态压缩【在更】

    一直都只会二进制的状态压缩……

    状态压缩?

    状态压缩,顾名思义,就是把一个大的状态压成相对来说内存更小的东西(通常来说是一个int数字)。而这样做又有什么好处呢?就是当状态的复制量很大,但修改次数相对较小时占优势。(试想一下如果不用回溯,那么dfs时每一层栈空间都带一个vis数组……)

    几种状态压缩

    三进制状态压缩

    loj#6177. 「美团 CodeM 初赛 Round B」送外卖2

    题目描述

    一张 n 个点 m 条有向边的图上,有 q 个配送需求,需求的描述形式为 (si,ti,li,ri),即需要从点 s_i​​ 送到 t_i, 在时刻 l_i​​ 之后(包括 l_i)可以在 s_i​​ 领取货物,需要在时刻 r_i​​ 之前(包括 r_i)送达 t_i ,每个任务只需完成一次。

    图上的每一条边均有边权,权值代表通过这条边消耗的时间。在时刻 0 有一个工作人员在点 1 上,求他最多能完成多少个配送任务。

    在整个过程中,可以认为领货跟交货都是不消耗时间的,时间只花费在路程上。当然在一个点逗留也是允许的。

    输入格式

    第一行,三个正整数 n,m,q(2≤n≤20,1≤m≤400,1≤q≤10)。
    接下来 m 行,每行三个正整数 ui,vi,ci(1≤ui,vi≤n,1≤ci≤20000),表示有一条从 ui​​ 到 vi​​ 耗时为 ci 的有向边。
    接下来 q 行,每行四个正整数 si,ti,li,ri(1≤si,ti≤n,1≤li≤ri≤10^6),描述一个配送任务。

    输出格式

    一个整数,表示最多能完成的任务数量。

    内存限制:32 MiB时间限制:200 ms标准输入输出
     

    题目分析

    我们首先可以发现n和q都是很小的,又注意到这题的时空限制很不寻常,于是可以大胆结合题意猜测一些想法。

    其实没什么好猜的我直接步入正题讲状态压缩算了就不讲我那zz的dfs了

    对于每一个送货任务来说,一共只有三种情况:0.货还没取;1.取货了没送到;2.已经送到了。

    于是考虑状压dfs。

    状压怎么压呢?形象一些就是一串长为q的三进制数,例如(021)(q=3),代表第一单货未取;第二单货已送到;第三单货正在配送。

    于是用一个int类型的state以十进制的方式存放状态。十进制?那么怎么提取各个状态呢?如同二进制状压一样,我们需要预处理三的各次幂。正是因为状态压缩这样的特性,所以它适用于需要频繁复制状态,而提取状态相对容易的情况。

    由于我第一次接触这种三进制状压时候,对于一些从未见过的操作颇有感触,那么就在代码里注释吧。

    hint:每一次可以接很多单(在路上跑的时候可以一次拿很多外卖)

    代码:

     1 #include<bits/stdc++.h>
     2 const int maxn = 21;  //n的最大值(一共多少点)
     3 const int max3 = 60003;//送货状态转为十进制数后的最大值,用于最优性剪枝
     4 
     5 struct node
     6 {
     7     int l,r,s,t;
     8     node() {}
     9     node(int a, int b, int c, int d):s(a),t(b),l(c),r(d) {}
    10 }a[maxn];        //存送外卖每一单的需求
    11 int ans,n,m,q;
    12 int f[maxn][max3],dis[maxn][maxn],base[maxn];      //base[]是3的各次幂,用于提取状态
    13 
    14 int read()
    15 {
    16     int num = 0;
    17     char ch = getchar();
    18     for (; !isdigit(ch); ch = getchar());
    19     for (; isdigit(ch); ch = getchar())
    20         num = (num<<1)+(num<<3)+ch-48;
    21     return num;
    22 }
    23 void dfs(int now, int state, int times)
    //now:现在在now这个上,注意是送货地图的点
    //state:现在所有送货的状态
    //times:现在已经花费的时间
    24 { 25 for (int i=1; i<=q; i++)                //检验在当前这个点,可以取送哪些货物 26 { 27 if (a[i].s==now && (state/base[i-1]%3==0) && times>=a[i].l) state += base[i-1];
           //现在在i单货物起点;i单货物状态为0(没有取货过);现在能够取这个货物;使这个状态+1(在三进制下变为1)
    28 if (a[i].t==now && (state/base[i-1]%3==1) && times<=a[i].r) state += base[i-1];
           //现在在i单货物终点;i单货物状态为1(已经取货了);现在送这个货物来得及;使这个状态+1(在三进制下变为2)
    29 } 30 if (f[now][state] < times) return;  //最优性剪枝 31 f[now][state] = times; 32 int cpy = state, cnt = 0; 33 while (cpy) 34 { 35 if (cpy%3==2) cnt++; 36 cpy /= 3; 37 }
        //提取当前状态中有多少外卖已经送到了
    38 if (ans < cnt) ans = cnt; 39 for (int i=1; i<=q; i++)        //接下去遍历每一单货物,考虑dfs的后继 40 { 41 if (state/base[i-1]%3==0){ 42 int tt = std::max(times+dis[now][a[i].s], a[i].l); 43 if (tt <= a[i].r) dfs(a[i].s, state, tt);  //如果这一单还没有送,并且现在立即赶过去还来得及,就dfs这一单
                                        //至于为什么这里不更改i单的状态,是因为不排除dfs这一单后能够同时送到其他单的情况。
                                        //所以我们放在每一次dfs开始的时候更新状态
    44 }else if (state/base[i-1]%3==1 && times+dis[now][a[i].t] <= a[i].r) 45 dfs(a[i].t, state, times+dis[now][a[i].t]); //如果这一单已经在配送过程中了,那么现在去配送这一单 46 } 47 } 48 int main() 49 { 50 scanf("%d%d%d",&n,&m,&q); 51 memset(dis, 0x3f3f3f3f, sizeof dis);    //送货地图上两点之间距离用 52 memset(f, 0x3f3f3f3f, sizeof f);      //最优性剪枝用 53 for (int i=1; i<=m; i++) 54 { 55 int x = read(), y = read(), z = read(); 56 if (dis[x][y] > z) dis[x][y] = z; 57 } 58 for (int k=1; k<=n; k++) 59 { 60 for (int i=1; i<=n; i++) 61 for (int j=1; j<=n; j++) 62 if (dis[i][j] > dis[i][k]+dis[k][j]) 63 dis[i][j] = dis[i][k]+dis[k][j]; 64 dis[k][k] = 0; 65 } 66 for (int i=1; i<=q; i++) 67 { 68 int ax = read(), b = read(), c = read(), d = read(); 69 a[i] = node(ax, b, c, d); 70 } 71 base[0] = 1;                  //预处理三的幂次(3^0,3^1,3^2……) 72 for (int i=1; i<=q; i++) 73 base[i] = base[i-1]*3; 74 dfs(1, 0, 0); 75 printf("%d ",ans); 76 return 0; 77 }

    另,待更,炮兵阵地

  • 相关阅读:
    【java 自动化测试】TestNg 介绍
    【java 自动化测试】第14章:持续集成
    【java 自动化】15章节:课程总结
    【性能测试】看了一个博客,总结一下
    【Dubbo】Dubbo 接口是什么? 与http 接口有什么区别?
    【jmeter】性能测试报告分析
    Netty 相关目录
    Netty 源码学习——EventLoop
    Netty 源码分析——ChannelPipeline
    Netty 源码学习——服务端流程分析
  • 原文地址:https://www.cnblogs.com/antiquality/p/8903800.html
Copyright © 2011-2022 走看看