动态规划——挖地雷
来自洛谷 P2196 [NOIP1996 提高组] 挖地雷
解题思路
由题目很容易想到的是通过动态规划来算出和某个点连接的所有点中的最大值再加上该点本身的值,但是对于整个遍历的方式,自己出现了错误。其实最简单的方式应当是类似于Floyd算法,对于每个点,都需要查找遍历其他的所有点,来找到对于每个点来说与其相连的最大值,并且记录下与其相连的点,最后再递归调用打印出挖的顺序。另外该题需要只记录 e i j e_{ij} eij其中( i < j i<j i<j),不然的话会出现重复的情况
模拟过程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TB737Vdk-1648368295255)(C:\Users\86180\AppData\Roaming\Typora\typora-user-images\image-20220327155605633.png)]
对于题目中给出的输入,做出模拟的过程:
当i=0时,与其相连的有1,2,3个点,找到最大的点,但其实这个时候所有点都还没有被赋值,所以最后只能得到res[0]=10
当i=1时,与其相连的点只有0,所以res[1]=res[0]+8=18 p[1]=0
当i=2时,与其相连的点只有0,其中3大于他所以暂且用不上,所以res[2]=res[0]+4=14 p[2]=0
当i=3时,与其相连的点有0,2,其中res[2]=14>res[0] ,故res[3]=res[2]+7=21 p[3]=2
当i=4时,与其相连的点有2,3, 其中 res[3]=res[2]+6=27 p[4]=3
综上我们可以看出 我们打印出的顺序一定是顺序的 并且每次相当于是向已有的点集中加点
代码实现
#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;
#define rep(i,s,n) for(int i=s;i<n;i++)
const int SIZE = 100;
int nums[SIZE];
int adjm[SIZE][SIZE];
int res[SIZE];
int p[SIZE];
int max_value = 0;
int max_index = 0;
void print(int x)
{
if (p[x] == -1)
{
printf("%d ", x + 1);
return;
}
print(p[x]);
if(x!=max_index)
printf("%d ",x+1);
else
printf("%d", x + 1);
}
int main()
{
memset(res, 0, sizeof(res));
memset(adjm, 0, sizeof(adjm));
memset(p, -1, sizeof(p));
int n;
scanf("%d", &n);
rep(i, 0, n)
{
scanf("%d", &nums[i]);
}
rep(i,0,n-1)
rep(j, i + 1, n)
{
int temp;
scanf("%d", &temp);
if (temp == 1)
{
adjm[i][j] = 1;//右边
}
}
rep(i, 0, n)
{
rep(j, 0, n)
{
if (adjm[j][i] == 1 && res[j] > res[i])
{
res[i] = res[j];
p[i] = j;
}
}
res[i] += nums[i];
if (res[i] > max_value)
{
max_value = res[i];
max_index = i;
}
}
print(max_index);
printf("\n%d", max_value);
return 0;
}
注意
洛谷的变量名似乎不能取为index,否则会编译报错
另外在cmp中,如果是>则代表升序