本文已参与「新人创作礼」活动,一起开启掘金创作之路。
链接:
⭐️www.luogu.com.cn/problem/P21…⭐️
几个点中有一系列路径,一个人可以从某个点开始走,直到走到尽头,每个点有一个值,问能够得到的最大值为多少
因为数据量较小,所以可以进行暴搜
1️⃣暴搜
- 可以以每个点为起点 : 所以在
dfs记录一些东西时需要进行回溯,本题需要回溯的是cnt值(记录了路径中的个数) - 代表
i到j是否可达 v: 记录路径的数组sum:代表以当前点结尾的路径中值的总和- 注意刚开始的起点
cnt也要回溯
暴搜
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
bool g[21][21],vis[30];
int a[25];
int p[25];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
memset(g, false, sizeof(g));
int n;
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 2; i <= n; i++)
{
for(int j = i; j <= n; j++)
{
int x;
cin >> x;
g[i - 1][j] = x;
}
}
int ans = 0;
vector<int> v;
int cnt = 0;
function<void(int, int)> dfs = [&](int x, int sum) -> void
{
for(int i = x + 1; i <= n; i++)
{
if(g[x][i])
{
p[++ cnt] = i;
dfs(i, sum + a[i]);
cnt --;
}
}
if(sum > ans)
{
ans = sum;
v.clear();
for(int i = 1; i <= cnt; i++) v.push_back(p[i]);
}
};
for(int i = 1; i <= n; i++)
{
p[++ cnt] = i;
dfs(i, a[i]);
cnt --;
}
for(int i = 0; i < v.size(); i++)
cout << v[i] << " \n"[i == v.size() - 1];
cout << ans << "\n";
return 0;
}
2️⃣DP
状态表示:
:以i为结尾的路径中总和的最大值
状态转移:
因为需要记录路径,进行状态转移时需要设置一个pre数组存储路径中的前驱节点,最后是用递归输出路径。
同时需要注意f[i]数组的初始化,因为有时候可以只选择一个点,如果没有初始化的话就会出错。
last:最优结果中路径的结尾节点
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int>a(n + 1),f(n + 1);
vector g(n + 1, vector(n + 1, 0));
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i < n; i++)
for(int j = i + 1; j <= n; j++)
{
int x;
cin >> x;
g[i][j] = x;
}
vector<int> pre(n + 1, 0);
int res = 0;
int last = 0;
for(int i = 1; i <= n; i++) f[i] = a[i];
for(int i = 2; i <= n; i++)
{
for(int j = 1; j < i; j++)
{
if(g[j][i] && f[j] + a[i] > f[i])
{
f[i] = f[j] + a[i];
pre[i] = j;
}
}
if(f[i] > res)
{
last = i;
res = f[i];
}
}
function<void(int)> print = [&](int x) -> void
{
if(pre[x] == 0)
{
cout << x ;
return;
}
print(pre[x]);
cout << " " << x;
};
print(last);
cout << "\n" << res << "\n";
return 0;
}