洛谷P3183食物链题解

不得不说,这是道很难减少时间复杂度的题,且这个题有点像一道拓扑排序题,但是这个难度标签有点低。

我们应该可以想到拓扑排序可能是这个题的正解,但是题目中有输出总数,因此我们就可以造一个数组表示从这个点出发向下有几个食物链,然后最后再输出每个入度为零且出度不为零的点所记忆化搜索到的点的个数。

我们先上70分的代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct zzz{
    int t,nex;
}e[200010<<1]; int head[100010],tot;
void add(int x,int y){
    e[++tot].t=y;
    e[tot].nex=head[x];
    head[x]=tot;
}
int in[100010],out[100010],vis[100010],ans;
int dfs(int x){
    if(vis[x]) 
    return vis[x];
    for(int i=head[x];i;i=e[i].nex){
        if(out[e[i].t]==0)
          vis[e[i].t]++;
        else vis[x]+=dfs(e[i].t);
    }
}
int main(){
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
        int x,y; scanf("%d%d",&x,&y);
        in[y]++; out[x]++;
        add(x,y);
    }
    for(int i=1;i<=n;i++){
        if(in[i]==0&&out[i]){
              dfs(i);
          }
        ans+=vis[i];
    }
    cout<<ans;
    return 0;
}

我们看这个代码觉得这不是加记忆化搜索了吗,为什么还是不够快呢。

因为这个记忆化他只加了一个,就是第一个,可是万一这一个始终实现不了,那就GG了,所以我们应该再加两个,即在每搜索到一个出度为0的点就返回1,且我们应该在遍历完这个点的所有边的时候加完之后再return一个。

所以做完这个题我们应该有了一个教训,便是记忆化搜索能加就加,别吝啬。

代码;

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
struct cym{
    int u;
    int v;
    int next;
}e[200100];
int head[100100],in_degree[100001],out_degree[100010],ans,total,dp[100010];//dp数组表示i这个点向下有几个出度为零的点,也就是有几条食物链 
void add(int a,int b)
{
    e[++total].u=a;
    e[total].v=b;
    e[total].next=head[a];
    head[a]=total;
}
int dfs(int x)
{
    int num=0;
    if(dp[x])
    return dp[x];
    if(!out_degree[x])
    return 1;//如果出度为零,就直接加1;
    for(int i=head[x];i;i=e[i].next)
    num+=dfs(e[i].v);//向下不断遍历,加上以x为起点的边其终点的dp数组的值 
    dp[x]=num;
    return dp[x];
}
int main()
{
    int n,m,u,v;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&u,&v);
        add(u,v);
        in_degree[v]++;
        out_degree[u]++;//记录出入度,别记反了。 
    }
    for(int i=1;i<=n;i++)
      if(!in_degree[i]&&out_degree[i])
        ans+=dfs(i);//有几个入度为零的点就算几次食物链,比如样例就只算算了一次 
    cout<<ans;
 } //@4017

代码后面有彩蛋。

转载于:https://www.cnblogs.com/liuwenyao/p/9236097.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值