题目:https://www.luogu.com.cn/problem/P3183
一道记忆化搜索的题。
大意是给出一个食物链,求食物链的条数。
很明显我们可以用dfs来解这个题,从入度为0的点开始,dfs去找,找到出度为0的点算是一条食物链。 用sign记录改点是否被访问,然后进行回溯。
但是这个题针对爆搜来说并不能过所有测试点。
code:
#include<bits/stdc++.h> using namespace std; const int nn = 1e5+10; vector<int> food[nn]; bool sign[nn]; int ans = 0; bool is_food[nn]; void dfs(int x) { if(food[x].size()==0) { ans++; return; } for(int i=0;i<food[x].size();i++) { if(!sign[food[x][i]]) { sign[food[x][i]]=true; dfs(food[x][i]); sign[food[x][i]]=false; } } } int main() { memset(is_food,false,sizeof is_food); int n,m,x,y; cin>>n>>m; while(m--){ scanf("%d%d",&x,&y); is_food[y] = true; food[x].push_back(y); } for(int i=1;i<=n;i++) { memset(sign,false,sizeof sign); sign[i] = true; if(food[i].size()>0&&!is_food[i]) dfs(i); } cout<<ans<<endl; }
那么就需要记忆化搜索来做。用临时sum记录该点通过的所有点的可行食物链。对食物进行dfs,这样每一个点能够能通过的食物链的数量就出来了。i
f(eat[x]) return eat[x];为记忆化搜索语句,当我们得出sum记录的该点通过的可行食物链的数量之后记录到记忆化中。eat[x] = sum;
code:
#include<bits/stdc++.h> using namespace std; const int nn = 1e5+10; vector<int> food[nn]; bool is_food[nn]; int eat[nn]; int ans = 0; int dfs(int x) { if(eat[x]) return eat[x]; int sum = 0; if(food[x].size()==0) return 1; for(int i=0;i<food[x].size();i++) { sum+=dfs(food[x][i]); } eat[x] = sum; return sum; } int main() { memset(is_food,false,sizeof is_food); int n,m,x,y; cin>>n>>m; while(m--){ scanf("%d%d",&x,&y); is_food[y] = true; food[x].push_back(y); } for(int i=1;i<=n;i++) { if(food[i].size()>0&&!is_food[i]) ans+=dfs(i); } cout<<ans<<endl; }