有两种方法,代码注释都很详细了直接上代码
一:记忆化搜索
#include<bits/stdc++.h>
using namespace std;
int t[15];
int n, m;
int a[400];
int mp[45][45][45][45];//mp[i][j][k][l]表示1号用i张,2号用j张,3号用k张,4号用l张的情况下,最多能拿多少分
int dfs(int step, int w)//step表示处理了几张卡片 w是现在的位置
{
if (mp[t[1]][t[2]][t[3]][t[4]])//如果已经有值
return mp[t[1]][t[2]][t[3]][t[4]];//直接返回
if (step == m)//都决定完了
return a[w];//返回此位置的值
int cnt = 0;
for (int i = 1;i <= 4; i++)
if (t[i] != 0)
{
t[i]--;
cnt = max(dfs(step + 1, w + i), cnt);//找后面所有情况中的最大值
t[i]++;
}
return mp[t[1]][t[2]][t[3]][t[4]] = cnt + a[w];//加上此位置的值为该状态下的最大值
}
int main()
{
scanf ("%d%d", &n, &m);
for (int i = 0;i < n; i++)
scanf ("%d", a + i);
for (int i = 0, x;i < m; i++)
{
scanf ("%d", &x);
t[x]++;
}
dfs(0, 0);
printf ("%d", mp[t[1]][t[2]][t[3]][t[4]]);
return 0;
}
二:用神奇的四重循环
#include<bits/stdc++.h>
using namespace std;
const int N = 45;
int n, m;
int f[N][N][N][N];//f[i][j][k][l]表示1号用i张,2号用j张,3号用k张,4号用l张时最多能拿多少分
int t[10];
int a[355];
int main()
{
scanf ("%d%d", &n, &m);
for (int i = 0;i < n; i++)
scanf ("%d", a + i);
for (int i = 0, x;i < m; i++)
{
scanf ("%d", &x);
t[x]++;
}
f[0][0][0][0] = a[0];//初始化
for (int t1 = 0;t1 <= t[1]; t1++)//循环1的张数
for (int t2 = 0;t2 <= t[2]; t2++)//循环2的张数
for (int t3 = 0;t3 <= t[3]; t3++)//循环3的张数
for (int t4 = 0;t4 <= t[4]; t4++)//循环4的张数
{
int tt = t1 + t2 * 2 + t3 * 3 + t4 * 4;//算出现在的位置 (我是从0开始的)
if (t1)//如果1的张数不唯一,就可以求出去1张1,并求最大值
f[t1][t2][t3][t4] = max(f[t1][t2][t3][t4], f[t1 - 1][t2][t3][t4] + a[tt]);
if (t2)//同上
f[t1][t2][t3][t4] = max(f[t1][t2][t3][t4], f[t1][t2 - 1][t3][t4] + a[tt]);
if (t3)//同上
f[t1][t2][t3][t4] = max(f[t1][t2][t3][t4], f[t1][t2][t3 - 1][t4] + a[tt]);
if (t4)//同上
f[t1][t2][t3][t4] = max(f[t1][t2][t3][t4], f[t1][t2][t3][t4 - 1] + a[tt]);
}
//结果在用 1号用t[1]张,2号用t[2]张,3号用t[3]张,4号用t[4]张里
//即在 f[t[1]][t[2]][t[3]][t[4]]里
printf ("%d", f[t[1]][t[2]][t[3]][t[4]]);
return 0;
}
标签:NOIP2010,int,题解,scanf,45,++,step,mp,P1541
From: https://www.cnblogs.com/Assassins-Creed/p/18018400