DFS进阶--记忆化搜索

  对于状态可以一次性遍历而确定的类型--推荐使用记忆化搜索,一般额外用一个数组(f[], f[][])来记录当前位置的状态。最近做了好几道记忆化搜索题\dp题,先挂上来一道觉得较典型的记录下学习的轨迹。原题:食物链~

  大量数据输入--快读优化;  

  复习了一下链式向前星存图:

  1)head[point]可看作以point为起点的所有边的集合(本质上就是point的某个出度),数组的大小为点的总数。head[point]为集合中边的编号的最大值。这个多用几次就会逐渐理解。

  2)edge[cur]数组存的是边,所以开的数组大小是边数。next用来将起点相同的边连成一个集合,point就像是一个泡沫板,起点相同的edge通过next像插气球一样插到point这泡沫板上,所以在访问point的所有边时,一直遍历next,直到泡沫板上的气球都被访问完。

  记忆化搜索:f[](一维,二维具体视情况而定)记录状态,再次遍历的时候就可以直接返回确定过的状态。

/**链式向前星 + 记忆化dfs搜索
    大数据记得要开long long, MLE就是这么来滴 ~
    链式向前星存的是边, cur为当前边的标号,note that 数组的大小要是边的数量!!
**/
#include <cstdio>
#include <cstring>
using namespace std;
#define uint unsigned int
#define ll long long
const int maxn = 100005;//总的最大点数,边数记得乘2,或者再开一个最大边数!
/**    next: 于当前边起点一样的另一条边的编号
    每个edge[i] 存的是一条边
    head[i]: 以i编号为起点的边的最大编号
    因为边的编号 cur 从0开始,所以 head[] 初始为-1,
    当然也可以使 cur 从1开始,这样就不必消耗时间将 head 初始化
**/
struct Edge{
    int to, next, w;
}edge[maxn<<1];    
ll f[maxn], sum; //状态方程
int head[maxn], n,m, cur=1;
uint in[maxn];
inline int read(){
    int ans = 0;
    char ch = getchar();
    while(ch<'0' || ch>'9') ch = getchar();
    while(ch>='0' && ch<='9'){
        ans = (ans<<3) + (ans<<1) + ch-'0';
        ch = getchar();
    }return ans;
}
/**    1.当前边进入from为起点的集合
    2.本边的另一个端点
    3.当前边的编号(from集中目前最大的编号)记录到 head[from].
**/
inline void addEdge(int from,int to){
    if(from == to) return;
    edge[cur].next = head[from];
    edge[cur].to = to; 
    head[from] = cur++; 
}
ll dfs(int q){
    if(f[q]) return f[q];
    if(!in[q] && !head[q]) return 0;//单个物种
    if(in[q] && !head[q]){ //结尾点
        f[q] = 1;
        return f[q];
    }
    ll tmp_sum = 0;
    for(int i=head[q];i;i=edge[i].next){
        tmp_sum += dfs(edge[i].to);
    }
    f[q] = tmp_sum;
    return f[q];
}
int main()
{
    n = read(), m = read();
    int u,v;
    for(int i=0;i<m;++i){
        u = read(), v = read();
        if(u ^ v) in[v] = true;
        addEdge(u,v);
    }
    for(int i=1;i<=n;++i){
        if(!in[i] && head[i])//食物链的首
            sum += dfs(i);
    }
    printf("%lld\n", sum);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/GorgeousBankarian/p/11050481.html
今日推荐