lsnu——dp题解
1.自然数拆分(计蒜客1248)
- 这道题和以前的一道题一摸一样,但是这道题是求具体的拆分方案
- 这道题用深度搜索,一直去搜索直到找到满足的情况。
有什么种实现方法 但这份代码我觉得最清楚明白
#include<iostream>
using namespace std;
const int N = 1e5;
int n;
int a[N];
void dfs(int sum , int len , int beginx)//sum 选的数的和 len 选了几个数 beginx 选数的起点
{
if(sum == n)
{
cout << n << "=" << a[0];
for(int i = 1 ; i <len ; i++)
cout << "+" << a[i];
cout << endl;
return ;
}
for(int i = 1 ; i <n ;i++)
{
if(sum + i <= n && i >= beginx)// 同一个数可以被多次选 ,又要满足单增
{
a[len] = i;
len ++;
dfs(sum + i , len , i);
len --;//回溯
}
}
}
int main()
{
cin >> n;
dfs(0 ,0 ,1);
return 0;
}
2.走马卒(计蒜客2118)
- 这是我在洛谷做的第一个题 现在终于做出来
- 看到的第一眼 可能会觉得这是一个非常模板的深度搜索题,但是只能过几个数据,会超时,那么就用更少循环的递推 DP吧
- f[i , j]储存的走到这个点有多少种走法 。状态的转移是 f [i , j] = f[i -1 , j] + f[i , j-1] 也就是点(i , j)由左边的点走过来和上边的点走过来,这个题的状态转移还有情况就是(i ,j)只能由左边或者上边走过来(受边界影响or“马”),那么f[i , j]=f[i-1 ,j]<上面走过来>或者 f[i , j]=f[i , j-1] , 但是题中由于边界和“马”的存在还有一些特殊的情况需要讨论
- 1 . (0 ,0~n)点也就是第一排的点 , 这一排的点只能由左边得来,同时如果在第一排中有“马” , 那么“马”后面的点也就不可能走到
//dp[i][j初始为0,前一个点不能为“马”点,如果前一个为“马”那么这个点的走法为
//0,那么后续的点也就都为0了
if(mapx[i][j] != INF && mapx[i][j-1] != INF) dp[i][j] = dp[i][j-1];
- 2.(0~n ,0)点也就是第一列的点,和上一种情况类所
if(mapx[i][j] != INF && mapx[i-1][j] != INF) dp[i][j] = dp[i-1][j];
- 3中间的点分别讨论 1.不能走到(上 左都是马)2.只能由一种情况走到3.左边和上边都能走到
if(mapx[i][j] == INF) dp[i][j] = 0;
else if(mapx[i-1][j] == INF && mapx[i][j-1] == INF) dp[i][j] = 0;
else if(mapx[i-1][j] == INF) dp[i][j] = dp[i][j-1];
else if(mapx[i][j-1] == INF) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i-1][j] + dp[i][j-1];
给一个样例的路线图解
完整代码
#include<iostream>
using namespace std;
const int N = 25;
const int INF = -1e5;
int bx , by , mx , my;
int mdirx[]={-2,-2,-1,-1,+1,+1,+2,+2};
int mdiry[]={-1,+1,-2,+2,-2,+2,-1,+1};
long long int mapx[N][N] , dp[N][N];//不开long long不能过
int main()
{
cin >> bx >> by >> mx >> my;
mapx[mx][my] = INF;
for(int i = 0;i < 8 ;i++)
{
int x = mx + mdirx[i];
int y = my + mdiry[i];
if(x >= 0 && x <= bx && y>= 0 && y <= by)
mapx[x][y] = INF;
}//记录马的影响坐标
for(int i = 0 ; i <= bx ; i++)
{
for(int j = 0 ; j <= by ; j++)
{
if(i == 0 && j == 0)dp[0][0] = 1;//初始化
else if(i == 0)
{
if(mapx[i][j] != INF && mapx[i][j-1] != INF) dp[i][j] = dp[i][j-1];//if让整个数组的边界都+1的话可以减少很多讨论,但是这个没有优化
//的最清晰吧 大家可以想想哦dp[0][x] = 0的话+ dp[0][x]也不会影响dp[0][x+1]
}
else if(j == 0)
{
if(mapx[i][j] != INF && mapx[i-1][j] != INF) dp[i][j] = dp[i-1][j];
}
else
{
if(mapx[i][j] == INF) dp[i][j] = 0;
else if(mapx[i-1][j] == INF && mapx[i][j-1] == INF) dp[i][j] = 0;
else if(mapx[i-1][j] == INF) dp[i][j] = dp[i][j-1];
else if(mapx[i][j-1] == INF) dp[i][j] = dp[i-1][j];
else dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
// cout << dp[i][j] << "(" << i <<"," << j << ")" << " ";
}
//cout << endl;//有兴趣的可以看看不同数据的图解
}
cout << dp[bx][by] << endl;
return 0;
}
我的写法肯定很劣质 , 还有更简单的更巧妙的做法,下面的链接有各种解法
https://www.luogu.com.cn/problem/solution/P1002
3.大盗阿福(计蒜客1227)
这是一个DP问题,解题关键是找到满足题目条件的状态表示。
dp[i]储存的是盗窃金额最大数,dp[i] : 前 i 个店中最优盗法 , 对于每个店都有盗或者不盗的选择(跟0 1背包问题很像)那么我们的状态
dp[ i ] = max(dp[i-1](不盗) , dp[i - 2] + a[i](盗));
注意边界 i - 2的处理;
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int t;
int main()
{
cin >> t;
while(t--)
{
int n ;
int a[N] , dp[N];
cin >> n;
for(int i = 1 ; i <= n ; i++)
cin >> a[i];
dp[1] = a[1];//i = 1直接选上,循环从i = 2开始
for(int i = 2 ; i <= n ; i++)
dp[i] = max(dp[i-1] , dp[i-2] + a[i]);
cout << dp[n] << endl;
}
return 0;
}
4.严酷的训练(计蒜客1739)
这是一个模板的 0 1 背包问题,在规定的时间内选择出最优的做题选择
dp[ i ][j]储存的是规定时间内在前 i 个问题且限制时间为j中选择的最大得分 , 对于每个问题我们都有选 or 不选
dp[i][j] = max(dp[i-1][j] , dp[i-1][j - 时间[i]] + 得分[i]) (还可以优化)
#include<iostream>
using namespace std;
const int N = 5500;
int k1,k2;
int m,n,limt;
int t[N];
int ch[N][2];
int dp[N];
int main()
{
cin >> k1 >> k2;
cin >> m >> n;
for(int i = 1; i<=n; i++)
{
int tm;
cin >> tm;
t[i] = (k2 / k1) * tm;
}//学生做第i题需要的时间
for(int i =1; i <= m; i++)
cin >> ch[i][0] >> ch[i][1];//记录该题的编号和得分
cin >> limt;
for(int i = 1; i<= m ;i++)
for(int j = limt; j >= t[ch[i][0]]; j--)//优化
dp[j] = max(dp[j],dp[j - t[ch[i][0]]] + ch[i][1]);
//f[i][j] = f[i-1][j],if (j > t[ch[i][0]])(for 从j=0开始)dp[i][j]
//=max(dp[i-1][j] , dp[i -1][j - t[ch[i][0]]] + ch[i][1]
cout << dp[limt] << endl;
return 0;
}