先找到最大值后进行路径标记,然后再找一遍最大值这种方法是不对的,
问的是两个路径没有重复点的时候,总共的最大值
同一时间点时不能出现相同的点,如何判断同一时间呢,
因为该点只会向右或者向下,所以判断时间相同的标准为两点的xy相同
两个相同的时候也是有可能出现的,因为可能是出发的节点或者是结束节点
for (int k = 2; k <= n + n; k ++ )
for (int i1 = 1; i1 <= n; i1 ++ )
for (int i2 = 1; i2 <= n; i2 ++ )
{
int j1 = k - i1, j2 = k - i2;
if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n)
{
if(i1 != i2 ||( i1 == n && i2 == n) || ( i1 == 1 && i2 == 1)){
int t = w[i1][j1];
if (i1 != i2) t += w[i2][j2];
int &x = f[k][i1][i2];
x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);
x = max(x, f[k - 1][i1 - 1][i2] + t);
x = max(x, f[k - 1][i1][i2 - 1] + t);
x = max(x, f[k - 1][i1][i2] + t);
}
}
}
最小费用流
最大上升子序列 DP O(n^2)
用贪心的话是 O(n logn)
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
int len = 0;
for (int i = 0; i < n; i ++ )
{
int l = 0, r = len;
while (l < r)
{
int mid = l + r + 1 >> 1;
if (q[mid] < a[i]) l = mid;
else r = mid - 1;
}
len = max(len, r + 1);
q[r + 1] = a[i];
}
printf("%d\n", len);
return 0;
}
每次更新长度为固定值的最后一个数的最小值
如果序列中的最大值比现在这个数大,就把该值加入到该序列中
最后得到的序列并不是真正的序列,而是用于维护序列 长度为 l 时 最后一个数的最小值 的序列
比如样例
6
2 13 4 1 5 6
最后序列是1 4 5 6 并不是真正的最大上升子序列,而是为了维护长度为4时的序列
两个字符串进行匹配,让其中一个等于另一个,有增加删除更换的操作,问最少操作次数
知道状态和集合如何表示就知道怎么做了
f [i, j] 代表 字符串1 前 i 个 ,字符串2 前 j 个 进行匹配需要的操作次数是多少
状态转移就很简单了
for (int i = 0; i <= m; i ++ ) f[0][i] = i;
for (int i = 0; i <= n; i ++ ) f[i][0] = i;
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= m; j ++ )
{
f[i][j] = min(f[i - 1][j] + 1, f[i][j - 1] + 1);
if (a[i] == b[j]) f[i][j] = min(f[i][j], f[i - 1][j - 1]);
else f[i][j] = min(f[i][j], f[i - 1][j - 1] + 1);
}
这个也是线性的DP,两个坐标表示两个字符串的位置,