2018程设模考2

A

分别记录纸币剩余数量判断是否能找零,因为数据比较弱所以对于5+5+5的情况没考虑也过了。

#include
using namespace std;
int main()
{
    int a=0,b=0,c=0;
    int n;
    int flag=1;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==5) a++;
        else if(n==10)
        {
            if(a)
            {
                a--;
                b++;
            }
            else
            {
                flag=0;
                printf("false");
                break;
            }
        }
        else
        {
            if(a&&b)
            {
                a--;
                b--;
                c++;
            }
            else
            {
                flag=0;
                printf("false");
                break;
            }
        }
    }
    if(flag) printf("true");
    return 0;
}

B

因为一次只能搬一块或者两块砖头,所以对于n块砖头的情况,只需要知道n-1和n-2块砖头有多少种方法,累加即可。dp[i]表示搬i块砖头有多少种方法,递推后输出dp[n]

#include
using namespace std;
int maxn=1e5+5;
int main()
{
    int dp[maxn];
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=1;i<=n;i++)
        {
            dp[i]+=dp[i-1];
            if(i-2>=0)
                dp[i]+=dp[i-2];
        }
        printf("%d",dp[n]);
    }
    return 0;
}

C

按照题意模拟即可,我给定了循环次数最多num=100。

#include
using namespace std;
int maxn=1e5+5;
int main()
{
    int num=100;
    int n;
    int flag=0;
    scanf("%d",&n);
    while(num--)
    {
        int temp=0;
        while(n)
        {
            temp+=(n%10)*(n%10);
            n/=10;
        }
        n=temp;
        if(temp==1)
        {
            flag=1;
            break;
        }
    }
    if(flag)
        printf("YES");
    else
        printf("NO");
    return 0;
}

D

dfs写完发现数据很大,果断超时了,先给出超时代码,后面再改。

#include
using namespace std;
typedef long long ll;
int maxn=1e6+5;
const int mod=1e9+7;
int n,a[105],num=1;
ll dfs(int x,int y,int p)
{
    ll ans=0;
    if(y==num) return 0;
    x+=p;
    if(x>n) return 0;
   // printf("i=%d %d\n",y,x);
    if(x==n) return 1;
    for(int i=1;i<=a[y+1];i++)
        ans=(ans+dfs(x,y+1,i))%mod;
    return ans;
}
int main()
{
    scanf("%d",&n);
    while(scanf("%d",&a[num])!=EOF)
    {
        num++;
    }
    ll temp=0;
    for(int i=1;i<=a[1];i++)
    {
        temp=(temp+dfs(0,1,i))%mod;;
    }
    printf("%lld",temp);
}

E

01背包的裸题,dp[i][j]表示前i个物品背包体积为j时最多能装价值为多少的物品,这里我省去了一维数组直接dp[j]表示体积为j的最大价值,为了保证状态互不影响第二层循环采取倒序,这里根据题意直接物品价值就是其体积。对背包有兴趣的可以百度一下背包九讲,关于如何降维以及为何倒序遍历都有详细解释。

#include
using namespace std;
int maxn=1e5+5;
const int mod=1e9+7;
int main()
{
    int dp[maxn];
    int n,a[maxn];
    scanf("%d",&n);
        int num=1;
        while(scanf("%d",&a[num])!=EOF)
        {
            //printf("%d\n",a[num]);
            num++;
        }
       // printf("%d\n",num);
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=num-1;i++)
        {
            for(int j=n;j>=a[i];j--)
            {
                dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
            }
        }
        printf("%d",dp[n]);
    return 0;
}

F

这题用到了动态规划的思想,dp[i][j]表示i个筛子掷出j点有多少种可能,那么我们考虑dp[i][j]是如何得到的。我们在掷出第i个筛子的时候会有六种情况,分别对应1~6点,那么得出转移方程

                                                       dp[i][j]=dp[i][j]+\sum_{k=j-6}^{j-1}dp[i-1][k]

这里得出了每种点数的可能方案数,但是我们求的是概率所以还要求出总的可能数,这个很简单就是6^n。

那么输出即可。

#include
using namespace std;
typedef long long ll;
int maxn=1e4+5;
const int mod=1e9+7;
int quick_pow(int a,int b)
{
    int ans=1,base=a;
    while(b)
    {
        if(b&1) ans*=base;
        base=base*base;
        b>>=1;
    }
    return ans;
}
int main()
{
    double dp[105][605];
    int n;
    scanf("%d",&n);
    for(int i=1;i<=6;i++)
        dp[1][i]=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=i;j<=6*i;j++)
        {
            for(int k=1;k<=6;k++)
                if(j>=k)
                dp[i][j]+=dp[i-1][j-k];
        }
    }
    int temp=quick_pow(6,n);
    for(int i=n;i<=6*n;i++)
    {
        printf("%d %.6f",i,dp[n][i]/(double)temp);
        if(i!=6*n) printf("\n");
    }
        

}

 

你可能感兴趣的:(思考题)