10.04——10.10ACM笔记

结束了搜索,开始刷DP的洛谷题。
BFS和DFS代表性的知识点:
1.八数妈问题:
求转化的最少步数,可用BFS解决,共有9!=362880种情况,关键是如何标记已经访问过的状态,保证每次搜索得到的状态都是最小的步数,这里可将字符串转化成对应的整数来处理,可用康托展开来节省存储空间。关键在于查重来减少时间复杂度。
2八皇后:
打表、DFS、回溯判断、模块化编程、算复杂度
关键在于如何递归和回溯。
问题难在很难取在矩阵中判断行,列,对角线。
判断皇后行列:如果在同一行,行号相同;在同一列,列好相同;在/对角线上,行列值之和相同;在\对角线上,行列之差相同。用a[i]=j来表示皇后在第i行第j列,用b[1…8]代表每一列只能有一个皇后,c[1…16],d[-7…7]控制同一对角线只能有一个皇后。
BFS和DFS都能实现,但DFS写起来简单。

DP:

1.管道取珠
dp[k][i][j]表示两个管道都取了k个球,第一个管道系统的第一个管道(上管道)取了i个球,自然第二个管道(第一个管道系统的下管道)取了k-i个球
同理:第二个管道系统的第一个管道取了j个球,第二个管道取了k-j个球
我们要得到相同序列,就要使得每次两侧取出的球都相同
防止数组空间会超,所以用滚动数组来优化,降低复杂度。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500 + 5;
const int mod = 1024523;
int dp[3][maxn][maxn];
int n, m;
char a[maxn], b[maxn];
 
int main() {
    cin >> n >> m;
    cin >> a + 1 ;
	cin >> b + 1;
    dp[0][0][0] = 1;
    for(int k = 1; k <= n + m; k++) 
	{
        memset(dp[k&1], 0, sizeof dp[k&1]);
        for(int i = 0; i <= n; i++) 
		{
            if(k - i < 0 || k - i > m) continue;
            for(int j = 0; j <= n; j++) 
			{
                if(k - j < 0 || k - j > m) continue;

                if(i && j && a[i] == a[j])dp[k & 1][i][j]=(dp[k & 1][i][j]+dp[!(k & 1)][i - 1][j - 1])%mod;
                if(i && k - j && a[i] == b[k - j])dp[k & 1][i][j] =(dp[k & 1][i][j]+ dp[!(k & 1)][i - 1][j])%mod;
                if(k - i && j && b[k - i] == a[j])dp[k & 1][i][j]=(dp[k & 1][i][j] + dp[!(k & 1)][i][j - 1])%mod;
                if(k - i && k - j && b[k - i] == b[k-j])dp[k & 1][i][j]=(dp[k & 1][i][j] + dp[!(k & 1)][i][j])%mod;
            }
        }
    }
    cout << dp[(n + m) & 1][n][n] << endl;
    return 0;
}

2.晨练计划
一看就是个二维DP,dp[i , j]表示第i秒疲劳度为j的最大距离。

首先dp[i, 0] = dp[i - 1, 0]是一定可以的。

然后就可以枚举疲劳度。

dp[i, 0] = max(dp[i, 0], dp[i - j, j]) j <= i

dp[i, j] = max(dp[i , j], dp[i - 1, j - 1] + a[i]) j <= M

#include <bits/stdc++.h>
#define MAXN 11111
#define MAXM 555
#define INF 1000000007
using namespace std;
int dp[MAXN][MAXM];
int a[MAXN];
int n, m;
int main()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for(int i = 1; i <= n; i++)
    {
        dp[i][0] = dp[i - 1][0];
        for(int j = 1; j <= m; j++)
        {
            if(i >= j) dp[i][0] = max(dp[i][0], dp[i - j][j]);
            dp[i][j] = max(dp[i - 1][j - 1] + a[i], dp[i][j]);
        }
    }
    printf("%d\n", dp[n][0]);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值