(BIT小学期)(25-30)

26.篮球练习

Description

小徐酷爱打篮球,在小学期的前两周半都在练习篮球。

今天,小徐想要练习如何突破。练习场地可由如下所示的网格图表示,图中的位置可用坐标表示。

其中A点(0,0)为小徐的起始位置,B点(n,m)为小徐想要到达的位置。

一起训练的还有场上的防守队员小彩,其位于C点。已知小徐行动时只能向右或向下前进,且当小徐相对于小彩的位置为Pi(i = 1,2…8)时,小徐会被抢断(注:在C点时同样会被抢断)。

注意,Pi坐标是会随C位置的变化而变化的,但相对位置是固定的

现在要求你计算小徐从A点到达B点且不被抢断的路径条数。假设小彩的位置是固定不动的,并不是小徐走一步小彩走一步。

Input

一行四个正整数,分别表示B点坐标和C点坐标。

Output

一个整数,表示所有的路径条数。

Hint

 对于全部的数据,1≤n,m≤20,0≤ C点的横纵坐标 ≤20。

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 6 6 3 3↵
以文本方式显示
  1. 6↵
1秒64M0

代码如下: 

#include <stdio.h>  
#include <stdlib.h>  
#include <math.h>  
  
int is_knight_move(int x1, int y1, int x2, int y2) {  
    return (abs(x1-x2)==2 && abs(y1-y2)==1) || (abs(x1-x2)==1 && abs(y1-y2)==2);  
}  
  
int is_blocked(int x, int y, int Cx, int Cy) {  
    return (x==Cx && y==Cy) || is_knight_move(x,y,Cx,Cy);  
}  
  
long long int count_paths(int Bx, int By, int Cx, int Cy) {  
    long long int dp[21][21] ={0};  
    if (!is_blocked(0,0,Cx,Cy)) dp[0][0]=1;  
    for (int i=1;i<=By;i++) {  
        if(!is_blocked(0,i,Cx,Cy)) dp[0][i]=dp[0][i-1];  
    }  
    for (int i=1;i<=Bx;i++) {  
        if(!is_blocked(i,0,Cx,Cy)) dp[i][0]=dp[i-1][0];  
    }  
    for (int i=1;i<=Bx;i++) {  
        for(int j=1;j<=By;j++) {  
            if(!is_blocked(i,j,Cx,Cy)) dp[i][j]=dp[i-1][j]+dp[i][j-1];  
        }  
    }  
    return dp[Bx][By];  
}  
  
int main()   
{  
    long long int Bx,By,Cx,Cy;  
    scanf("%lld %lld %lld %lld",&Bx,&By,&Cx,&Cy);  
    printf("%lld\n",count_paths(Bx,By,Cx,Cy));  
    return 0;  
}

27. 方向标

一位木匠收到了一份木制指示牌的订单。每块木板必须与前一块垂直对齐,要么与前一个箭头对齐,要么用专门设计的螺丝固定在对面。两块木板必须重叠。木匠写下了一个整数序列来编码设计师发送的草图,但这个序列并不能确定一个唯一的模型,他已经扔掉了原始草图。对他来说,看似琐碎的任务变成了一个大拼图。

该序列(包含1+N个元素)对从符号底部到顶部的(N)个箭头进行编码。第一个元素是底部箭头左侧的位置。剩下的N个元素定义了箭头从下到上的起始位置:第i个元素是第i个箭头基所在的位置。例如,所示的两个符号(左边和右边)可以用2 6 5 1 4编码。

由于一块板必须与前一块板垂直对齐(要么与前一个箭头的底部对齐,要么与另一侧对齐),如果顺序为2 6 5 1 4 3,则第五个箭头可以用螺钉固定在1(指向右侧)或4(指向左侧),箭头底部为3。

如果顺序是2 3 1,则第二个箭头只能用螺钉固定在3处,指向左侧,因为连续的板必须重叠。

所有箭头都是相似的,设计师告诉木匠,它们的底部和底部箭头的左侧都位于不同的垂直线上,总共形成了1.(N+1)的排列。这就是为什么木匠忽略了细节,只写下排列(例如,2 6 5 1 4 3)。

给定木匠写下的数字序列,计算可以制作的方向箭头符号的数量。由于这个数字可能很大,所以必须以2147483647为模来写。序列中的第二个整数始终大于第一个整数(底部箭头始终指向右侧)。

输入

第一行具有一个整数N,第二行包含从1到N+1的整数的排列。同一行中的整数由一个空格分隔。

输出

输出具有单个行,该行具有可以由给定排列描述的不同符号的数目(模2147483647)。

注意

1<=N<=2000

代码如下:

#include <stdio.h>    
#include <stdlib.h>    
#define mo 2147483647    
#define Num 2005    
long long dp[Num][Num];    
long long head[Num];    
long long max(long long a, long long b)    
{    
    if(a>b)  return a;    
    else  return b;    
}    
long long min(long long a,long long b)    
{    
    if(a>b)  return b;    
    else  return a;    
}    
int main()    
{    
    long long N,L,R,ans=0;    
    int i,j;    
    scanf("%lld",&N);    
    scanf("%lld",&head[0]);    
    dp[1][head[0]]=1;    
    for(i=1;i<=N;i++)    
    {    
        scanf("%lld",&head[i]);    
        for(j=0;j<N+2;j++)    
        {    
            L=min(head[i-1],j);    
            R=max(head[i-1],j);    
            if(head[i]>=R)  dp[i][L]=(dp[i-1][j]+dp[i][L])%mo;    
            else if(head[i]<=L)  dp[i][R]=(dp[i-1][j]+dp[i][R])%mo;     
            else    
            {    
                dp[i][L]=(dp[i-1][j]+dp[i][L])%mo;  
                dp[i][R]=(dp[i-1][j]+dp[i][R])%mo;    
            }    
        }    
    }    
    for(i=0;i<N+2;i++)  ans=(ans+dp[N][i])%mo;    
    printf("%lld\n",ans);    
}

28.考试

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 1000 5↵
  2. 800 2↵
  3. 400 5↵
  4. 300 5↵
  5. 400 3↵
  6. 200 2↵
以文本方式显示
  1. 3900↵
1秒64M0
测试用例 2以文本方式显示
  1. 22415 2↵
  2. 2824 3↵
  3. 2485 3↵
以文本方式显示
  1. 15927↵
1秒64M0

代码如下: 

#include<stdio.h>  
int max(int m,int n)  
{  
    return m>n?m:n;  
}  
int main()  
{  
    int n,m,i,j,ans=-1;  
    scanf("%d %d",&n,&m);  
    int t[m],w[m],dp[n+1],v[m];  
    for(i=0;i<=n;i++)  dp[i]=0;  
    for(i=0;i<m;i++){  
        scanf("%d %d",&t[i],&w[i]);  
        v[i]=t[i]*w[i];  
    }  
    for(i=0;i<m;i++)  for(j=n;j-t[i]>=0;j--)  dp[j]=max(dp[j],dp[j-t[i]]+v[i]);  
    printf("%d\n",dp[n]);  
} 

 29. 一道简单背包题

代码如下: 

#include <stdio.h>      
#include <stdlib.h>      
#define Num 2005      
int p[Num],dp[Num][Num];      
int main()      
{      
    int n,V,i,j,mod;      
    scanf("%d %d",&n,&V);      
    dp[0][0]=1;      
    for(i=1;i<=n;i++)      
    {      
        scanf("%d",&p[i]);      
        for(j=0;j<V;j++)  dp[i][j]=(dp[i-1][j]+dp[i][j])%10000000;      
        for(j=0;j<V;j++)      
        {      
            mod=(j+p[i])%V;      
            dp[i][mod]=(dp[i-1][j]+dp[i][mod])%10000000;      
        }      
    }      
    printf("%d\n",dp[n][0]-1);      
}

 

30. 有一个人前来买瓜

军训这么累,当然要吃瓜啦。

有一个小军前来买瓜。

众所周知,YHW水果摊里的西瓜的瓜皮子和瓜粒子都是金粒子做的。小军当然想获得尽可能多的金粒子。

一共有n个瓜,每个瓜有重量w,成熟度v,金粒子数量g。

虽然小军的钱是无限的,但他的电动车载重是有限的,因此他不能买总重量超过W的瓜。

"我开水果摊的,能卖给你生瓜蛋子? ——YHW

因此,当小军买的瓜的总成熟度小于V时,YHW并不会把瓜卖给他。

具体的:水果摊一共有n个瓜,每个瓜有重量w,成熟度v,金粒子数量g。一共有q次询问,每次询问给出两个值W、V,小军要选取n个瓜的子集,使总重量 Σw≤W,总成熟度Σv≥V,求 Σg
的最大值。

Input

第一行输入两个整数,q(1≤n≤100,1≤q≤100),代表瓜的数量和询问数量。

接下来n行,每行三个整数,第i行的三个整数为i,vi,gi(1≤wi,vi,gi≤100),分别代表第i个瓜的重量,成熟度和价值。

接下来q行,输入两个整数,V(1≤W,V≤500),代表一组询问。

Output

输出一共有q行,每行一个整数,分别代表每组询问的最大金粒子数总和,若无合法的买法则输出-1。

测试输入期待的输出时间限制内存限制额外进程
测试用例 1以文本方式显示
  1. 5 1↵
  2. 2 4 5↵
  3. 4 3 3↵
  4. 1 3 2↵
  5. 3 4 3↵
  6. 3 2 5↵
  7. 10 10↵
以文本方式显示
  1. 15↵
1秒64M0

 代码如下:

#include <stdio.h>  
#include <stdlib.h>  
#define Num 505  
int max(int a,int b){  
    return a>b?a:b;  
}  
int min(int a,int b){  
    return a<b?a:b;  
}  
int w[Num],v[Num],g[Num];  
int main()  
{  
    int n,q,W,V,i,j,k,o,ans;  
    int dp[505][505];  
    memset(dp,-1,sizeof(dp));  
    dp[0][0]=0;  
    scanf("%d %d",&n,&q);  
    for(i=0;i<n;i++)  scanf("%d %d %d",&w[i],&v[i],&g[i]);  
    for(i=0;i<n;i++){  
        for(j=500;j>=0;j--){  
            for(k=500;k>=0;k--){  
                if(dp[j][k]>=0&&j+w[i]<=500)  dp[j+w[i]][min(k+v[i],500)]=max(dp[j][k]+g[i],dp[j+w[i]][min(k+v[i],500)]);  
            }  
        }  
    }  
    for(o=q;o>0;o--){  
        scanf("%d %d",&W,&V);  
        ans=-1;  
        for(j=0;j<=W;j++){  
            for(k=V;k<=500;k++)  ans=max(ans,dp[j][k]);  
        }  
        printf("%d\n",ans);  
    }  
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值