简单dp题单的最后一道题!
从前有一个人,她想dp,后来写着写着,就写成了topo。
本题这里提供两种做法,拓扑排序和DPS+DP(记忆化搜索),使用vector数组存图,一维变长。
拓扑排序
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
// topo
int n, m, ans;
int in[5005], out[5005], f[5005];
vector<int> food[5005];
queue<int> q;
int main(){
scanf("%d%d", &n, &m);
int a, b;
for(int i = 1; i <= m; i++){
scanf("%d%d", &a, &b);
food[a].push_back(b);
out[a] ++;
in[b] ++;
}
for(int i = 1; i <= n; i ++){
if(in[i]==0){
q.push(i);
f[i] = 1;
}
}
while (!q.empty()){
int p = q.front();
q.pop();
for(int i = 0; i < food[p].size(); i ++){
int x = food[p][i];
f[x] += f[p];
f[x] %= 80112002;
in[x] --;
if(in[x] == 0){
if(out[x]==0){
ans += f[x];
ans %= 80112002;
}
else q.push(x);
}
}
}
printf("%d\n", ans);
return 0;
}
输入的时候记一下每个点的出度和入度,将入度为0
的点入队,f[i]
的值等于所有指向它的点的f[pre]
之和。f[i]
每加上一个f[pre]
,把点i
的入度-1
,如果出度为0
说明到头啦,加在ans
上,当入度为0
时入队。注意不要忘记%80112002
!
DPS+DP(记忆化搜索)
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
//dfs+dp
int n, m, ans;
int in[5005], out[5005], dp[5005];
vector<int> food[5005];
int dfs(int x){
if(out[x]==0) return 1;
if(dp[x]!=0) return dp[x];
for(int i = 0; i < food[x].size(); i ++){
dp[x] += dfs(food[x][i]);
dp[x] %= 80112002;
}
return dp[x];
}
int main(){
scanf("%d%d", &n, &m);
int a, b;
for(int i = 1; i <= m; i++){
scanf("%d%d", &a, &b);
food[a].push_back(b);
out[a] ++;
in[b] ++;
}
for(int i = 1; i <= n; i ++){
if(in[i] == 0){
ans += dfs(i);
ans %= 80112002;
}
}
printf("%d\n", ans);
return 0;
}
同样也是输入的时候记一下每个点的出度和入度,从入度为0
的点开始搜,dp[i]
表示以点i
为起点时食物链的数量。搜的时候,如果出度为0
说明到头了,直接返回1;如果已经搜过了,直接返回dp[]
;否则继续搜索。注意不要忘记%80112002
!
∠( ᐛ 」∠)_
要坚强要加油哦!!