DP

我将通过几个我做过的dp题型,来全方面的重新介绍题意和重新介绍解法。以此来为DP最一份总结。过于简单的不予介绍,此总结只适合有基础的人。

因为我也没基础,所以需要有基础的人才能看懂


DP求最长方案与方案路径

P2196 [NOIP 1996 提高组] 挖地雷

题意:在一个 $ N\le20 $ 的图里面,可以从任意一点出发,只能移动到一个编号比当前节点大且联通的节点,求最长路径之节点之和与路径

解法:将问题给拆分出两个部分,一个部分是如何求出最长路径,第二部分是如何求出路径。

最长路径之和

由题意可知,一点出发,只会移动到一个比当前节点大且联通的一个节点。故而我们可以通过画图得知(图请脑补),一个节点的选择只有要么从 本节点开始,要么 从之前节点转移 所以轻易可得状态转移方程

1
2
3
if(dist[j][i] && dp[i] < dp[j]+a[i] ){
dp[i] = max(dp[i], dp[j]+a[i]);
}
记录路径

非常简单,我们可以另开一个函数,标明这个节点从哪里转移过来,而初始我们预处理成自己,而后递归求出

1
2
3
4
5
6
7
8
9
void resolve(int res){
if(res==look_dist[res]){
cout << res << ' ' ;
return ;
}
resolve(look_dist[res]) ;
cout << res<< ' ' ;

}
1
for(int i = 1 ; i <= n ; i++)look_dist[i] = i;
1
2
3
4
if(dist[j][i] && dp[i] < dp[j]+a[i] ){
dp[i] = max(dp[i], dp[j]+a[i]);
look_dist[i] = j ;
}

结束

拓扑排序

P4017 最大食物链计数

给你一张图,给你节点与有向边,不会出现环的情况,求路径数。

拓扑排序(Topological sorting)要解决的问题是如何给一个有向无环图的所有节点排序

特征:1.从入度为零的点开始。2.就是求路径数。3.出度为零的点的路径总数和就是答案。

首先,我们需要存图,然后将入度和出度数量进行记录。而后将入度为零的点作为起点 注意需要无环 然后压入队列中,进行方案数统计,并且重复之前步骤。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<bits/stdc++.h>
using namespace std ;
const int N = 5e3 + 10 ;
//a b , a代表被吃的动物 , b 代表吃的动物 。
//既然如此 , a被b吃的意思就是正好有了一条路,可以被转移!
//5e3 2e7 不能采用现在想的规划,我的还没到最优
int dp[N] ;
const int mod = 80112002 ;
int n , m ; int in[N] , out[N] ; //入度出度
vector<int>ad[N] ;
queue<int> q ; //拓扑排序需要队列,根据先进先出的作用
int ans ;
int num[N] ; //ans
void solve(){
cin >> n >> m ;
for(int i = 1 ; i<= m ; i++){
int x , y; cin >> x >> y ;
++in[y] ; ++out[x] ; //x 出去 , y 进来
ad[x].push_back(y);
}
for(int i = 1 ; i<= n ; i++){
if(!in[i]){
num[i] = 1 ;
q.push(i) ; //压入零出度的地方
}
}
while(!q.empty()){
int tot = q.front() ;
q.pop() ;
for(const auto & y : ad[tot]){
--in[y] ; //入度减少,因为y点是路
num[y] = (num[y]+ num[tot])% mod ; //入出
if(!in[y])q.push(y);//压入栈
}
}
for(int i = 1 ; i<= n ; i++){
if(!out[i])ans=(ans% mod+num[i]%mod)%mod ;
}
cout << ans ;
return ;
}
int main(){
int t = 1 ;
// cin >> t ;
while(t--){
solve() ;
}
return 0 ;
}

最大字段和问题

给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大。

例如

1
2
7
2 -4 3 -1 2 -4 3

可以注意到,这种就是两种状态要么选,要么不选。什么时候选,选了不如不选的情况。即

1
dp[i] =max(dp[i-1]+ a[i] , a[i]) ;

结束