P1002 过河卒
棋盘上 AAA 点有一个过河卒,需要走到目标 BBB 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 CCC 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,AAA 点 (0,0)(0, 0)(0,0)、BBB 点 (n,m)(n, m)(n,m),同样马的位置坐标是需要给出的。
题目链接:https://www.luogu.com.cn/problem/P1002
我的思路:一开始我以为这是一道宽度优先搜索,但是后来觉得宽度优先搜索应该是搜索最短路径长度,然后想是不是深度优先搜索,深度优先搜索应该是用于是否能够到达终点的
后来看了解析才知道是动态规划。动态规划就是一个填表的操作,这次要填的二维表格的大小和棋盘一样大,每个格子里的内容是到达该点有多少种方法。
由此可以得到状态转移方程是:
S[2][2] = 0
{\text{S[2][2] = 0}}
S[2][2] = 0
S [ i ] [ j ] = max ( S [ i ] [ j ] , S [ i − 1 ] [ j ] + S [ i ] [ j − 1 ] ) S[i][j] = \max (S[i][j],S[i - 1][j] + S[i][j - 1]) S[i][j]=max(S[i][j],S[i−1][j]+S[i][j−1])
为什么去第一个是S[2][2]是因为马走日,避免超出数组的界限
需要注意的地方:
这个S数组中的值可能很大,因此需要用unsigned long long来表示。
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n,m;
int x,y;
unsigned long long s[30][30];
bool d[30][30];
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 main()
{
scanf("%d%d%d%d",&n,&m,&x,&y);
n+=2;m+=2;
x+=2;y+=2;
d[x][y]=1;
//标记马的控制范围
for(int i=1;i<=8;i++)
{
d[x+fx[i]][y+fy[i]]=1;
}
s[2][2]=1;
//动态规划填表
for(int i=2;i<=n;i++)
{
for(int j=2;j<=m;j++)
{
if(d[i][j])
{
continue;
}
s[i][j]=max(s[i][j],s[i-1][j]+s[i][j-1]);
}
}
cout<<s[n][m]<<endl;
//printf("%llu\n",s[n][m]);
return 0;
}
P1015 回文数
题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个十进制数 565656,将 565656 加 656565(即把 565656 从右向左读),得到 121121121 是一个回文数。
又如:对于十进制数 878787:
STEP1:87+78=16587+78=16587+78=165
STEP2:165+561=726165+561=726165+561=726
STEP3:726+627=1353726+627=1353726+627=1353
STEP4:1353+3531=48841353+3531=48841353+3531=4884
在这里的一步是指进行了一次 N 进制的加法,上例最少用了 4 步得到回文数 4884。
写一个程序,给定一个 N(2≤N≤10 或 N=16)进制数 M(100 位之内),求最少经过几步可以得到回文数。如果在 30步以内(包含 30 步)不可能得到回文数,则输出 Impossible!。
输入格式
两行,分别是 N,M。
输出格式
如果能在 30步以内得到回文数,输出格式形如 STEP=ans,其中 ans 为最少得到回文数的步数。
否则输出 Impossible!。
我的思路:
这个是一个高精度的题目,无法使用int一类的数字来表示,因此需要使用char数组来表示很大的数。
输入部分:将需要计算的m输入为一个char数组,其中m[0]对应的就是数字的最低位,很神奇吧,明明数字的最低位是最后一个输入的,但是却存在了char数组的第0位,但是这样也为后面的计算带来了方便,数字就是向高位递增的啦,很神奇吧!还有就是需要处理输入的数据,因为输入的是字符,但是我们需要计算的是数字,所以对应了-‘0’和-‘A’+10的操作。
首先需要自己定义加法操作,由于加法操作最多进一位,所以当计算到最高位的时候需要判断是否进位,如果进位,那么char数组的长度就要加一。
然后就是直接30次模拟了
代码
#include<iostream>
#include<cstring>
using namespace std;
int n;
char m[500];
char m_reverse[500];
int len;
bool ishui(char number[500])
{
//int len=strlen(number);
for(int i=0;i<len;i++)
{
if(number[i]!=number[len-i-1])
{
return false;
}
}
return true;
}
void add()
{
//int len = strlen(m);
//求的
for(int i=0;i<len;i++)
{
m_reverse[i]=m[len-i-1];
}
//len+=2;
for(int i=0;i<len;i++)
{
m[i]=m[i]+m_reverse[i];
if(m[i]>=n)
{
m[i+1]++;
m[i]=m[i]-n;
if(i==len-1)
{
len++;
}
}
}
//while(!m[len-1]) len--;
}
int main()
{
cin>>n>>m;
len=strlen(m);
//cout<<m<<endl;
int ans=0;
bool isok=false;
for(int i=0;i<len;i++)
{
if(m[i]>='0'&&m[i]<='9')
m[i]-='0';
else
{
m[i]=m[i]-'A'+10;
}
}
for(int i=0;i<30;i++)
{
bool flag = ishui(m);
//cout<<flag<<endl;
if(flag)
{
cout<<"STEP="<<ans<<endl;
isok=true;
break;
}
add();
ans++;
}
if(!isok)
{
cout<<"Impossible!"<<endl;
}
return 0;
}
P1003 铺地毯
题目地址:https://www.luogu.com.cn/problem/P1003
这一题思路很奇葩,直接从最后一张地毯开始看是否包含(x,y)这个点就好啦!
代码
#include<iostream>
using namespace std;
typedef unsigned long long ull;
ull n;
ull a[10005];
ull b[10005];
ull g[10005];
ull k[10005];
ull x,y;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>a[i]>>b[i]>>g[i]>>k[i];
}
cin>>x>>y;
bool isok=false;
for(int i=n-1;i>=0;i--)
{
if(x>=a[i]&&x<=a[i]+g[i]&&y>=b[i]&&y<=b[i]+k[i])
{
cout<<i+1;
isok = true;
break;
}
}
if(!isok)
{
cout<<-1;
}
return 0;
}