动态规划
Skyzhou666 · · 算法·理论
关于动态规划
线性DP
最长上升子序列LIS(
dp[x]表示以a[x]为结尾的最长上升子序列,将求n个数的LIS转化为n-1个数的LIS,以此类推
#include <iostream>
#define MAXN 1001
using namespace std;
int a[MAXN], dp[MAXN];
int main()
{
int n;
cin >> n;
for(int x = 0; x < n; x++) cin >> a[x];
dp[0] = 1;
for(int x = 0; x < n; x++)
for(int y = 0; y < x; y++)
if(a[y] < a[x]) dp[x] = max(dp[x], dp[y]+1);
int ans = 0;
for(int x = 0; x < n; x++) ans = max(ans, dp[x]);
cout << ans << endl;
return 0;
}
#include <iostream>
#define MAXN 1001
#define INF 0x7fffffff
using namespace std;
int a[MAXN], dp[MAXN];
int main()
{
int n;
cin >> n;
for(int x = 0; x < n; x++)
{
cin >> a[x];
dp[x] = INF;
}
int ans = 1;
dp[0] = 0;
for(int x = 0; x < n; x++)
{
int l = 0, r = ans, mid;
if(a[x] > dp[ans]) dp[++ans] = a[x];
else
{
while(l < r)
{
mid = (l + r) >> 1;
if(dp[mid] > a[x]) r = mid;
else l = mid + 1;
}
//cout << x << " " << l << endl;
dp[l] = min(a[x], dp[l]);
}
}
cout << ans << endl;
return 0;
}
最长公共子序列LCS(
dp[i][j]表示前缀子串a[1~i]和b[1~j]的最长公共子序列长度
#include <iostream>
#define MAXN 1001
using namespace std;
int a[MAXN], b[MAXN], dp[MAXN][MAXN];
int main()
{
int n;
cin >> n;
for(int x = 1; x <= n; x++) cin >> a[x];
for(int x = 1; x <= n; x++) cin >> b[x];
for(int x = 1; x <= n; x++)
{
for(int y = 1; y <= n; y++)
{
dp[x][y] = max(dp[x-1][y], dp[x][y-1]);
if(a[x] == b[y]) dp[x][y] = max(dp[x][y], dp[x-1][y-1]+1);
}
}
cout << dp[n][n] << endl;
return 0;
}
线性dp
01背包
P1048 采药(01背包模板题)
#include <iostream>
using namespace std;
int dp[1001], t[1001], v[1001];
int main()
{
int T, M;
cin >> T >> M;
for(int x = 0; x < M; x++) cin >> t[x] >> v[x];
//关键在这两行
for(int x = 0; x < M; x++)
for(int y = T; y >= t[x]; y--)
dp[y] = max(dp[y], dp[y-t[x]]+v[x]);
cout << dp[T] << endl;
return 0;
}
_
第一层循环遍历每颗草药,代表对第i颗药做规划,第二层循环则是用采第i颗药的时间对
01背包中的方案数问题(弱化版)
现在有
#include <iostream>
#define MAXN 1001
using namespace std;
int dp[MAXN], a[MAXN];
int main()
{
int n, m;
cin >> n >> m;
for(int x = 0; x < n; x++) cin >> a[x];
dp[0] = 1;
for(int x = 0; x < n; x++)
for(int y = m; y >= a[x]; y--) dp[y] += dp[y-a[x]];
cout << dp[m] << endl;
return 0;
}
完全背包
哈哈不过就是01背包把倒序改成正序罢了刚才瞎调试的时候试出来了((
P1616 疯狂的采药(完全背包模板题)
#include <iostream>
using namespace std;
long long f[10000001], tm[10001], val[10001];
int main()
{
int t, n;
cin >> t >> n;
for(int x = 0; x < n; x++) cin >> tm[x] >> val[x];
for(int x = 0; x < n; x++)
for(int y = tm[x]; y <= t; y++)
f[y] = max(f[y], f[y-tm[x]] + val[x]);
cout << f[t] << endl;
return 0;
}
思路和上题一样,只不过第二层循环遍历时是正序,因为每颗药可以无限次采摘,只要能限定时间内最大价值填满就行。 卡long long(