原题链接:Problem - 987C - Codeforces
题目大意:给你n个数a1,a2...an还有与其分别对应的b1,b2..bn。求所有的满足i < j < k,a[i] < a[j] < a[k]的三个数的b[i] + b[j] + b[k]的最小值。
方法一:
用两个dp:
第一个dp得到所有可以作为第二个数的值(a[i] +a[j]),并放到bb[]数组中,当然如果这个数不能作为第二个数,bb[]此时为INF;
第二个dp直接设res = INF,然后如果能找到第三个数就直接算出和更新res。
代码:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define ios ios::sync_with_stdio(false);cin.tie(0); cout.tie(0);
typedef pair<int, int> PII;
const double pi = acos(-1.0);
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define rrep(i, n) for (int i = n; i >= (1); --i)
typedef long long ll;
#define sqar(x) ((x)*(x))
const int N = 3010;
int a[N], b[N], bb[N]; //b[],作为第一个值的贡献 bb[]作为第二个值的贡献
int main(){
int n;
cin >> n;
rep(i, n) cin >> a[i];
rep(i, n) cin >> b[i];
for(int i = 2; i < n; i++){ //i为作为第二个点的下标
bb[i] = INF; //如果下标为i的这个数不会作为第二个数,f[i]就会是INF
for(int j = 1; j < i; j++){ //j是找到的第一个点的下标
if(a[j] < a[i]) bb[i] = min(bb[i], b[i] + b[j]);
}
}
int res = INF;
for(int i = 3; i <= n; i++) //i作为第三个点的下标 j作为第二个点的下标
for(int j = 2; j < i; j++) if(a[j] < a[i]) res = min(res, b[i] + bb[j]);
if(res == INF) cout << -1;
else cout << res << endl;
return 0;
}
当然我还看到了有个作者写的,我感觉这个dp思维更厉害!好强!
下面的方法二是这个作者的方法:
C. Three displays(简单dp)_a1046765624的博客-CSDN博客
方法二:
思路:
dp一下。
dp【i】【j】是以i结尾的 j 元组的最小价值。然后状态转移一下就行了。
dp【i】【2】=min(dp【i】【2】,dp【k】【1】+w【i】)(1<=k<i)
dp【i】【3】=min(dp【i】【3】,dp【k】【2】+w【i】)(1<=k<i)
#include <bits/stdc++.h>
using namespace std;
const int maxn=3100;
const int INF=0x3f3f3f3f;
int a[maxn],w[maxn];
int dp[maxn][4];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
dp[i][1]=w[i];
}
for(int i=1;i<=n;i++)
{
dp[i][2]=INF;
dp[i][3]=INF;
for(int j=1;j<i;j++)
{
if(a[i]>a[j])
{
dp[i][2]=min(dp[j][1]+w[i],dp[i][2]);
dp[i][3]=min(dp[j][2]+w[i],dp[i][3]);
}
}
}
int sum=INF;
for(int i=3;i<=n;i++)
{
if(dp[i][3]==INF)continue;
sum=min(sum,dp[i][3]);
}
if(sum==INF)printf("-1\n");
else printf("%d\n",sum);
return 0;
}