递归就可以分类讨论了!
#include
int arr1[10001],arr2[10001];
int n,ans;
int check(int x){
if(arr1[x-1]+arr1[x]+arr1[x+1]==arr2[x])
//判断当前情况下是否满足arr2数组
return 1;
return 0;
}
void dfs(int k){
if(k==n+1){
//搜索结束条件,如果直到最后一个判断都符合条件,说明方案可行
if(check(n))
ans++;
return;
}
arr1[k]=1;
if(k==1||check(k-1))
//假设该格子有雷,且判断无误,继续搜下一个格子
//必须check(k-1),因为如果check(k),该格子下方还不确定是否有雷,画个图就懂了
dfs(k+1);
arr1[k]=0;
if(k==1||check(k-1))
//假设该格子无雷,且判断无误,继续搜下一个格子
dfs(k+1);
return;
}
int main(){
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&arr2[i]);
//arr2数组的第一个位置是空着的
dfs(1);
//所以dfs从第二个位置开始搜索
printf("%d",ans);
return 0;
}
方法一:DFS,参考了以前需要回溯的那道题,不过时间复杂度太大,得了40分
#include
int Bx,By,Mx,My;
long long ans;
const int d[8][2]={-2,-1,-1,-2,1,-2,2,-1,2,1,1,2,-1,2,-2,1};
void DFS(int x,int y){
int i;
if(x==Bx+1||y==By+1) return;
for(i=0;i<8;i++)
if(x+d[i][0]==Mx&&y+d[i][1]==My) return;
if(x==Mx&&y==My) return;
if(x==Bx&&y==By){
ans++;
return;
}
DFS(x+1,y);
DFS(x,y+1);
return;
}
int main(){
scanf("%d%d%d%d",&Bx,&By,&Mx,&My);
DFS(0,0);
printf("%lld",ans);
return 0;
}
方法二:dp,但是c编译器第三组数据莫名其妙结果为0,但cpp正常,可参考:
#include
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;
int i,j;
unsigned long long f[40][40];
//f[i][j]代表从A点到(i,j)会经过的线路数
int s[40][40];
//判断这个点有没有马盯着
int max(int a,int b){
if(a>=b) return a;
else return b;
}
int main(){
scanf("%d%d%d%d",&bx,&by,&mx,&my);
bx+=2;by+=2;mx+=2;my+=2;
//坐标+2以防越界
f[2][2]=1;
//初始化
s[mx][my]=1;
//标记马的位置
for(i=1;i<=8;i++)
s[mx+fx[i]][my+fy[i]]=1;
for(i=2;i<=bx;i++){
for(j=2;j<=by;j++){
if(s[i][j])continue;
f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]);
//状态转移方程
}
}
printf("%llu",f[bx][by]);
return 0;
}
方法三:比用max好理解的dp,适合参考:
#include
int b[30][30];
//用于标记
long long a[30][30];
//用于记录走到某一个格子共有多少种路线
int dx[8]={2,1,-1,-2,-2,-1,1,2};
int dy[8]={1,2,2,1,-1,-2,-2,-1};
int n,m,x,y;
int main(){
int i,j;
scanf("%d%d%d%d",&n,&m,&x,&y);
b[x][y]=1;
for(i=0;i<=7;i++){
//标记马和马挡道的位置
if(x+dx[i]>=0&&x+dx[i]<=n&&y+dy[i]>=0&&y+dy[i]<=m){
b[x+dx[i]][y+dy[i]]=1;
}
}
int k=0;
while(!b[k][0]&&k<=n){
//最左一列,到达的方式只可能有一种,学
a[k++][0]=1;
}
int l=0;
while(!b[0][l]&&l<=m){
//最上一列,到达的方式只可能有一种,学
a[0][l++]=1;
}
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(b[i][j]){
a[i][j]=0;
//被标记处路线数为0
}
else{
a[i][j]=a[i-1][j]+a[i][j-1];
//状态转移方程,核心是把大问题拆成小部分,学
//对每一个格子,都考虑上一步是从左边来的,还是从上边来的
}
}
}
printf("%lld",a[n][m]);
return 0;
}
没什么好说的
#include
int l,n,i,min,max,arr[5001];
int main(){
scanf("0 0",&l,&n);
if(n==0){
//特判
printf("0");
return 0;
}
for(i=1;i<=n;i++) scanf("%d",&arr[i]);
if(arr[1]<=l/2){
min=arr[1];
max=l-arr[1]+1;
}
else{
min=l-arr[1]+1;
max=arr[1];
}
for(i=2;i<=n;i++){
if(arr[i]<=l/2){
if(arr[i]>=min) min=arr[i];
if(l-arr[i]>=max) max=l-arr[i]+1;
}
else{
if(arr[i]>=max) max=arr[i];
if(l-arr[i]>=min) min=l-arr[i]+1;
}
}
printf("%d %d",min,max);
return 0;
}
该题是我第一次接触分治算法,大概理解了
#include
int n, k, a[1201][1201];
void dfs(int x1, int y1, int x2, int y2, int X, int Y)
{
if (x2 - x1 == 1 && y2 - y1 == 1) //变成了2*2
{
if (X == x1 && Y == y1) printf("%d %d 1\n", x2, y2);
if (X == x1 && Y == y2) printf("%d %d 2\n", x2, y1);
if (X == x2 && Y == y1) printf("%d %d 3\n", x1, y2);
if (X == x2 && Y == y2) printf("%d %d 4\n", x1, y1);
return;
}
int x = (x2 - x1 + 1) / 2 + x1 - 1;
int y = (y2 - y1 + 1) / 2 + y1 - 1;
//先求出中间点
if (X <= x && Y <= y) //真公主在此时中间点的左上角
{
dfs(x1, y1, x, y, X, Y); //在左上角面积为原来1/4的小正方形区域内搜索(x,y都为原先的1/2)
printf("%d %d 1\n", x + 1, y + 1);
dfs(x + 1, y1, x2, y, x + 1, y); //右上角
dfs(x + 1, y + 1, x2, y2, x + 1, y + 1); //右下角
dfs(x1, y + 1, x, y2, x, y + 1); //左下角
}
if (X <= x && Y > y) //真公主在此时中间点的左下角
{
dfs(x1, y + 1, x, y2, X, Y); //左下角
printf("%d %d 2\n", x + 1, y);
dfs(x1, y1, x, y, x, y); //左上角
dfs(x + 1, y1, x2, y, x + 1, y); //右上角
dfs(x + 1, y + 1, x2, y2, x + 1, y + 1); //右下角
}
if (X > x && Y <= y) //真公主在此时中间点的右上角
{
dfs(x + 1, y1, x2, y, X, Y); //右上角
printf("%d %d 3\n", x, y + 1);
dfs(x + 1, y + 1, x2, y2, x + 1, y + 1); //右下角
dfs(x1, y1, x, y, x, y); //左上角
dfs(x1, y + 1, x, y2, x, y + 1); //左下角
}
if (X > x && Y > y) //真公主在此时中间点的右下角
{
dfs(x + 1, y + 1, x2, y2, X, Y); //右下角
printf("%d %d 4\n", x, y);
dfs(x1, y1, x, y, x, y); //左上角
dfs(x1, y + 1, x, y2, x, y + 1); //左下角
dfs(x + 1, y1, x2, y, x + 1, y); //右上角
}
}
int main()
{
int x, y;
scanf("%d%d%d", &k, &x, &y);
n = 1;
for (int i = 1; i <= k; i++)
n *= 2;
dfs(1, 1, n, n, x, y);
return 0;
}
懒得思考了…看看人家是怎么设数组的吧…
#include
#include
int m,n,k,l,d;
int x[1005],y[1005];
//横纵坐标数组
int c[1005],o[1005];
//桶排要用的数组
int min(int a,int b){
if(a>=b) return b;
else return a;
}
int main(){
int i,j,p;
scanf("%d%d%d%d%d",&m,&n,&k,&l,&d);
for(i=1;i<=d;i++) {
int xi,yi,pi,qi;
scanf("%d%d%d%d",&xi,&yi,&pi,&qi);
if(xi==pi)
x[min(yi,qi)]++;
//x和y数组存放的是,如果隔开这两排/列,能分开几组说话的同学
//需要取min,过道与前一个坐标保持一致
else
y[min(xi,pi)]++;
}
for(i=1;i<=k;i++){
//桶排
int maxn=-1;
//为了求出每次的最大值,需要每次扫一遍
for(j=1;j<m;j++)
if(y[j]>maxn){
maxn=y[j];
p=j;
}
y[p]=0;
//这种情况归为0,继续找次于这一种的下一种过道划分方式,直到找到k种
c[p]++;
}
for(i=1;i<=l;i++){
int maxn=-1;
for(j=1;j<n;j++)
if(x[j]>maxn){
maxn=x[j];
p=j;
}
x[p]=0;
o[p]++;
}
for(i=0;i<1005;i++)
//输出结果
if(c[i])
printf("%d ",i);
printf("\n");
for(i=0;i<1005;i++)
if(o[i])
printf("%d ",i);
return 0;
}
“最优策略”即每个格子都要走过,这时候只需要判断总格子的个数,个数为奇数则xx胜,个数为偶数则xx胜…
#include
int n;
int main(){
while(1){
scanf("%d",&n);
if(n==0) return 0;
if(n%2) printf("Bob\n");
else printf("Alice\n");
}
return 0;
}
学习四舍五入的方法
#include
//#include
long long n,arr[100001],m,i,p1,s1,s2,sum,p2;
int main(){
scanf("%lld",&n);
for(i=1;i<=n;i++) scanf("%lld",&arr[i]);
scanf("%lld%lld%lld%lld",&m,&p1,&s1,&s2);
for(i=1;i<=n;i++) sum+=arr[i]*(m-i);
sum+=s1*(m-p1);
p2=m+(int)(sum*1.0/s2+0.5*(sum>0?1:-1));
// if(sum>0) p2=m+round(sum*1.0/s2);
// else p2=m-round(sum*1.0/s2);
// 用round函数实现四舍五入,只能得72分,原因未知
if(p2>n) p2=n;
if(p2<1) p2=1;
printf("%lld",p2);
return 0;
}
#include
int m,n,i,j,ans;
char people[100001][11];
int cmd[100001][2],dir[100001];
int main(){
scanf("%d%d",&n,&m);
for(i=0;i<n;i++)
scanf("%d%s",&dir[i],&people[i]);
for(i=0;i<m;i++)
for(j=0;j<2;j++)
scanf("%d",&cmd[i][j]);
for(i=0;i<m;i++){
if(cmd[i][0]+dir[ans]==0){
//如果指令和初始朝向都为0,则顺时针转
if(ans>=cmd[i][1]) ans-=cmd[i][1];
else ans=ans+n-cmd[i][1];
}
else if(cmd[i][0]+dir[ans]==1){
//如果指令和初始朝向一个为0,一个为1,则顺时针转
if(ans+cmd[i][1]>=n) ans=ans-n+cmd[i][1];
else ans+=cmd[i][1];
}
else if(cmd[i][0]+dir[ans]==2){
//如果指令和初始朝向都为1,则顺时针转
if(ans>=cmd[i][1]) ans-=cmd[i][1];
else ans=ans+n-cmd[i][1];
}
}
printf("%s",people[ans]);
return 0;
}
#include
int n,arr[101],check[10001],ans;
int main(){
int i,j,k;
scanf("%d",&n);
for(i=0;i<n;i++) scanf("%d",&arr[i]);
for(i=0;i<n;i++){
for(j=0;j<n;j++){
if(i==j) continue;
for(k=0;k<n;k++){
if(k==i||k==j) continue;
if(arr[j]+arr[k]==arr[i]){
if(check[arr[i]]==0) ans++;
check[arr[i]]=1;
}
}
}
}
printf("%d",ans);
return 0;
}
#include
int n,arr[101],count;
int main(){
int i;
scanf("%d",&n);
for(i=0;i<=n;i++) scanf("%d",&arr[i]);
for(i=0;i<=n;i++){
if(n-i!=1&&n-i!=0){
if(arr[i]<0&&arr[i]!=-1){
count++;
printf("%dx^%d",arr[i],n-i);
}
else if(arr[i]==-1){
count++;
printf("-x^%d",n-i);
}
else if(arr[i]>0&&arr[i]!=1&&count!=0){
count++;
printf("+%dx^%d",arr[i],n-i);
}
else if(arr[i]==1&&count!=0){
count++;
printf("+x^%d",n-i);
}
else if(arr[i]>0&&arr[i]!=1&&count==0){
count++;
printf("%dx^%d",arr[i],n-i);
}
else if(arr[i]>0&&arr[i]==1&&count==0){
count++;
printf("x^%d",n-i);
}
else if(arr[i]==0);
}
else if(n-i==1){
if(arr[i]<0&&arr[i]!=-1){
count++;
printf("%dx",arr[i],n-i);
}
else if(arr[i]==-1){
count++;
printf("-x");
}
else if(arr[i]>0&&arr[i]!=1&&count!=0){
count++;
printf("+%dx",arr[i]);
}
else if(arr[i]>0&&arr[i]!=1&&count==0){
count++;
printf("%dx",arr[i]);
}
else if(arr[i]>0&&arr[i]==1&&count!=0){
count++;
printf("+x");
}
else if(arr[i]>0&&arr[i]==1&&count==0){
count++;
printf("x");
}
else if(arr[i]==0);
}
else if(n-i==0){
if(arr[i]>0&&count!=0){
count++;
printf("+%d",arr[i]);
}
if(arr[i]>0&&count==0){
count++;
printf("%d",arr[i]);
}
else if(arr[i]<0){
count++;
printf("%d",arr[i]);
}
}
}
return 0;
}
C语言中的高精度乘法
上方博客可作参考,虽然和如下代码没有什么关系…
#include
int i,j,n,len=1,arr[10001];
int main(){
arr[1]=1;
scanf("%d",&n);
for(i=1;i<=n+1;i++){
for(j=1;j<=len;j++)
arr[j]*=2;
for(j=1;j<=len;j++){
if(arr[j]>9){
if(arr[len]>9) len++;
arr[j+1]+=arr[j]/10;
arr[j]%=10;
}
}
}
arr[1]-=2;
// 这里只做了一次判断,其实不严谨
if(arr[1]<0){
arr[1]=arr[1]+10-2;
arr[2]--;
}
for(i=len;i>0;i--) printf("%d",arr[i]);
return 0;
}
#include
int s, i, n, t, k, r, w[100001], x[300002], y[300002];
int main(){
scanf("%d",&n);
while(n--){
scanf("%d%d", &t, &k);
while(k--){
y[++r] = t;
scanf("%d", &x[r]);
if(!w[x[r]])s++;
w[x[r]]++;
}
while (t - y[i] >= 86400)
if (!--w[x[i++]])s--;
/*
这句话与下面这段代码等效:
w[x[i]]--; 国籍为当前这个人的国籍的人的数量-1
if(!w[x[i]])s--; 如果当前这个人的国籍没人,那么答案-1
i++; 换下一个人
*/
printf("%d\n", s);
}
return 0;
}
#include
int m,n;
const int dx[]={1,1,1,0,0,-1,-1,-1};
const int dy[]={1,0,-1,1,-1,0,1,-1};
char arr[101][101];
int main(){
int i,j,k;
scanf("%d%d",&m,&n);
for(i=0;i<m;i++)
scanf("%s",arr[i]);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
if(arr[i][j]!='*'){
arr[i][j]-=15;
for(k=0;k<8;k++)
if(arr[i+dx[k]][j+dy[k]]=='*')
arr[i][j]++;
}
for(i=0;i<m;i++)
printf("%s\n",arr[i]);
return 0;
}