ACM暑假集训总结2

动态规划入门

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≤200 \le0≤ 马的坐标 \le 2020![这是题目的图](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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值