动态规划入门
1.背包问题
2.简单路径方案问题
高精度入门
1. 高精加减乘除问题
.
.
.
动态规划入门水题
题目描述
棋盘上 AA 点有一个过河卒,需要走到目标 BB 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 CC 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,AA 点 (0, 0)(0,0)、BB 点 (n, m)(n,m),同样马的位置坐标是需要给出的。
现在要求你计算出卒从 AA 点能够到达 BB 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 BB 点坐标和马的坐标。
输出格式
一个整数,表示所有的路径条数。
输入输出样例
输入
6 6 3 3
输出
6
说明/提示
对于 100 \%100% 的数据,1 \le n, m \le 201≤n,m≤20,0 \le0≤ 马的坐标 \le 20≤20。![这是题目的图](https://img-blog.csdnimg.cn/20200801125159359.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ2Nzk1NjIy,size_16,color_FFFFFF,t_70)
此题的动态转移方程较简单
方法一:变换坐标将向右下全移动两格防止数组越界(比较坑)!!
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
long long a[30][30];int n,m,mx,my;
int main()
{ cin>>n>>m>>mx>>my;
n+=2;m+=2;mx+=2;my+=2;
for(int i=2;i<=n;i++){
for(int j=2;j<=m;j++){
a[i][j]=a[i][j-1]+a[i-1][j];
a[2][2]=1;a[mx][my]=0;
a[mx+2][my-1]=0;a[mx+2][my+1]=0;a[mx-2][my+1]=0;a[mx-2][my-1]=0;
a[mx+1][my-2]=0;a[mx+1][my+2]=0;a[mx-1][my+2]=0;a[mx-1][my-2]=0;
}
}
cout<<a[n][m]<<endl;
return 0;
}
方法二
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int fx[] = {0, -2, -1, 1, 2, 2, 1, -1, -2};
const int fy[] = {0, 1, 2, 2, 1, -1, -2, -2, -1};
int bx, by, mx, my;
ull f[2][30];//第一维大小为 2 就好
bool s[30][30];
int main(){
scanf("%d%d%d%d", &bx, &by, &mx, &my);
bx += 2; by += 2; mx += 2; my += 2;
f[1][2] = 1;//初始化
s[mx][my] = 1;
for(int i = 1; i <= 8; i++)
s[ mx + fx[i] ][ my + fy[i] ] = 1;
for(int i = 2; i <= bx; i++){
for(int j = 2; j <= by; j++){
if(s[i][j]){
f[i & 1][j] = 0;//被马拦住了记住清零
continue;
}
f[i & 1][j] = f[(i - 1) & 1][j] + f[i & 1][j - 1];
//新的状态转移方程
}
}
printf("%llu\n", f[bx & 1][by]);
//输出的时候第一维也要 按位与 一下,即 bx&1
return 0;
}
动态规划入门-完全背包
题目就不用多描述
#include<iostream>
#include<cstring>
#include<algorithm>
int m,n;
int v[10000005],t[10000005];
int dp[10000005];
using namespace std;
int main(){
cin>>m>>n;
for(int i=1;i<=n;i++){
cin>>t[i]>>v[i];
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;j++){
if(j>=t[i]){
dp[j]=max(dp[j-t[i]]+v[i],dp[j]); }
else{
dp[j]=dp[j];
}
}
}cout<<dp[m]<<endl;
return 0;
}
高精度
加法
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=2e2+4;
char s1[maxn]={};
char s2[maxn];
int a[maxn];
int b[maxn];
int c[maxn];
int main()
{
scanf("%s %s",s1,s2);
int len1=strlen(s1);
for(int i=0;i<len1;++i){
a[i]=s1[len1-i-1]-'0';
}
int len2=strlen(s2);
for(int i=0;i<len2;++i){
b[i]=s2[len2-i-1]-'0';
}
int len=max(len1,len2)+1;
int jw=0;
for(int i=0;i<len;i++){
c[i]=a[i]+b[i]+jw;
jw=c[i]/10;
c[i]=c[i]%10;
}
for(int i=len-1;i>=0;i--){
if(0==c[i]&&len>1)
len--;
else break;
}
for(int i=len-1;i>=0;i--){
printf("%d",c[i]);
}
printf("\n");
return 0;
}
减法
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e4+10;
char s1[maxn];
char s2[maxn];
char tem[maxn];
int a[maxn];
int b[maxn];
int c[maxn];
int main(){
scanf("%s %s",s1,s2);
int lena=strlen(s1);int lenb=strlen(s2);
if((lena<lenb)||(lena==lenb&&strcmp(s1,s2)<0)){
cout<<"-";
strcpy(tem,s1);
strcpy(s1,s2);
strcpy(s2,tem);
lena=strlen(s1);
lenb=strlen(s2);
}
for(int i=0;i<lena;i++){
a[i]=s1[lena-i-1]-'0';
}
for(int i=0;i<lenb;i++){
b[i]=s2[lenb-i-1]-'0';
}
for(int i=0;i<lena;i++){
if(a[i]<b[i]){
a[i+1]--;
a[i]+=10;
}
c[i]=a[i]-b[i];
}
for(int i=lena-1;i>=0;i--){
if(0==c[i]&&lena>1)lena--;
else break;
}
for(int i=lena-1;i>=0;i--){
printf("%d",c[i]);
}
cout<<endl;
return 0;
}
乘法
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200+4;
char s1[MAXN] = {};
char s2[MAXN] = {};
int a[MAXN] = {};
int b[MAXN] = {};
int c[2*MAXN] = {};
int main() {
scanf("%s %s", s1, s2);
bool flaga = false;
if ('-'==s1[0]) {
flaga = true;
strcpy(s1, &s1[1]);
}
bool flagb = false;
if ('-'==s2[0]) {
flagb = true;
strcpy(s2, &s2[1]);
}
if ((true==flaga && false==flagb) || (false==flaga && true==flagb)) {
printf("-");
}
int lena = strlen(s1);
for (int i=0; i<lena; i++) {
a[lena-i-1]=s1[i]-'0';
}
int lenb = strlen(s2);
for (int i=0; i<lenb; i++) {
b[lenb-i-1]=s2[i]-'0';
}
int jw;
for (int i=0; i<lena; i++) {
jw=0;
for (int j=0; j<lenb; j++) {
c[i+j] = a[i]*b[j]+jw+c[i+j];
jw = c[i+j]/10;
c[i+j] %= 10;
}
c[i+lenb]=jw;
}
int lenc=lena+lenb;
for (int i=lenc-1; i>=0; i--) {
if (0==c[i] && lenc>1) {
lenc--;
} else {
break;
}
}
for (int i=lenc-1; i>=0; i--) {
printf("%d", c[i]);
}
printf("\n");
return 0;
}
除法
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 300+4; //根据题目的最大值。+4为了防止A+B出现进位
char s1[MAXN] = {};//存储字符串
char s2[MAXN] = {};//存储字符串
int tmp[MAXN] = {};//交换用字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[MAXN] = {};//存储和B
int compare(int a[], int b[]) {
//索引为0的数据为数组长度
if (a[0]>b[0]) {
return 1;
} else if (a[0]<b[0]) {
return -1;
}
//逐位比较
for (int i=a[0]; i>0; i--) {
if (a[i]>b[i]) {
return 1;
} else if (a[i]<b[i]) {
return -1;
}
}
return 0;
}
void numcpy(int a[],int b[],int dest) {
//将数组右移,使两个数组右端对齐,形参q数组储存右移后的结果
for (int i=1;i<=a[0];i++) {
b[i+dest-1] =a[i];
}
b[0] = a[0]+dest-1;
}
int main() {
scanf("%s %s", s1, s2);//读入字符串
//处理负数
bool flaga = false;//乘数a的符号
if ('-'==s1[0]) {
flaga = true;
strcpy(s1, &s1[1]);//删除负号
}
bool flagb = false;//乘数b的符号
if ('-'==s2[0]) {
flagb = true;
strcpy(s2, &s2[1]);//删除负号
}
//处理输出的负号
if (true==flaga && false==flagb) {
//商为负数
printf("-");
}
//处理乘数1
int len = strlen(s1);
a[0] = len;
for (int i=0; i<len; i++) {
a[len-i]=s1[i]-'0';
}
//处理乘数2
len = strlen(s2);
b[0] = len;
for (int i=0; i<len; i++) {
b[len-i]=s2[i]-'0';
}
if (0==compare(a,b)) {
//两数相等
printf("1\n0\n");
return 0;
} else if (-1==compare(a,b)) {
//被除数小,除数大
printf("0\n");//输出除数
if (true==flaga) {
printf("-");
}
printf("%s\n", s1);
return 0;
} else {
c[0] = a[0]-b[0]+1;
for (int i=c[0]; i>0; i--) {
memset(tmp, 0, sizeof(tmp));
//高位对齐
numcpy(b,tmp,i);
//
while (compare(a, tmp)>=0) {
c[i]++;
//减法
for (int j=1; j<=a[0]; j++) {
if (a[j]<tmp[j]) {
a[j+1]--;
a[j]+=10;
}
a[j]-=tmp[j];
}
int k=a[0];
while (a[k]==0) {
k--;
}
a[0]=k;
}
}
//控制最高位的0
while (c[0]>0 && c[c[0]]==0) {
c[0]--;
}
}
//逆序打印输出商和余数
for (int i=c[0]; i>0; i--) {
printf("%d", c[i]);
}
printf("\n");
if (0==a[0]) {
printf("0\n");
} else {
if (true==flaga) {
printf("-");
}
for (int i=a[0]; i>0; i--) {
printf("%d", a[i]);
}
printf("\n");
}
return 0;
}