首页 > 试题广场 >

K点游戏

[编程题]K点游戏
  • 热度指数:2474 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
小招喵某日闲来无事,想验一下自己的人品,于是给自己定了一个游戏规则:
这个游戏有三个因素:N,K,W
游戏开始的时候小招喵有0点,之后如果发现自己手上的点不足K点,就随机从1到W的整数中抽取一个(包含1和W),抽到哪个数字的概率都是相同的。
重复上述过程,直到小招喵获得了K或者大于K点,就停止获取新的点,这时候小招喵手上的点小于等于N的概率是多少?

输入:N = 5, K = 1, W = 5
输出:1.00000
说明:开始有0点,不足1点,从[1,5]中随机取一个整数(一共5个数字,所以每个数字取到的概率都是1/5),获得后得分无论如何都大于了1点,停止,概率为1

输入:N = 6, K = 1, W = 10
输出:0.60000
说明:开始有0点,不足1点,从[1,10]中随机取一个整数(一共10个数字,所以每个数字取到的概率都是1/10),获得后有6/10的概率小于6点,且满足大于1点的条件,概率为0.6

输入描述:
输入为3个整数,分别对应N,K,W,中间用空格隔开

其中0 <= K <= N <= 10000,1 <= W <= 10000


输出描述:
输出为概率值,保留5位小数
示例1

输入

21 17 10

输出

0.73278
详解在这篇博客:
看完步骤,很容易写出代码。
if __name__=='__main__':
    n, k, w = list(map(int, input().split()))
    dp = [0]*(k+w) 
    for i in range(k, n+1):
        dp[i] = 1 
    s = min(w, n-k+1)
    for i in range(k-1, -1, -1):
        dp[i] = s / w
        s += dp[i] - dp[i+w]
    print(round(dp[0],5))


发表于 2019-08-09 10:47:26 回复(1)

n, k, w = list(map(int, input().split()))
dp = [0]*(k+w) #k-1能达到的最大值为k+w-1
for i in range(k, n+1):
    dp[i] = 1
s = min(w, n-k+1)
for i in range(k-1, -1, -1):
    dp[i] = s / w 
    s += dp[i] - dp[i+w]
print(round(dp[0], 5))
编辑于 2019-02-27 13:07:46 回复(2)
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n, k, w;
    scanf("%d%d%d", &n, &k, &w);
    double dp[k+w];
    for(int i=k;i<k+w;i++)
        if(i<=n)
            dp[i] = 1;
        else
            dp[i] = 0;
    double t = min(n-k+1, w);
    for(int i=k-1;i>=0;i--){
        dp[i] = t / w;
        t += dp[i] - dp[i+w];
    }
    printf("%.5f\n", dp[0]);
    return 0;
}

发表于 2020-11-01 01:34:11 回复(0)
/*
@奋起的小孩 的思路
dp[i]表示起始i点满足要求(小于n)的概率
dp[i] = (1/w)*sum(dp[i+1],dp[i+2],...,dp[i+10])
by the way:输出格式有坑,与示例不符 
*/
#include<bits/stdc++.h>
using namespace std;
#define N 10000

int main()
{
//    freopen("input.txt", "r", stdin);
    int n, k, w, i;
    cin >> n >> k >> w;
    vector<float> dp(k + w);
    for(i = k; i <= n; i++)
        dp[i] = 1;  //都满足要求,概率为1
    for(i = n + 1; i < k + w; i++)
        dp[i] = 0;  //不满足要求,概率为0
    float temp = min(n - k + 1, w); //求[k,k+w]的和
    for(i = k - 1; i >= 0; i--) {
        dp[i] = temp / w;
        temp += dp[i] - dp[i + w]; //每次只能抽到[1,w],一次不能到达的减掉
    }
// printf("%.5f",dp[0]);
    float ans = int(dp[0] * 100000 + 0.5) / 100000.0;
    cout<<ans<<endl;
    return 0;
}


编辑于 2019-07-11 20:55:00 回复(3)
亲测可用:
#include <bits/stdc++.h>
using namespace std;
 
int main(){
    int n, k, w;
    scanf("%d%d%d", &n, &k, &w);
    double dp[k+w];
    for(int i=k;i<k+w;i++)
        if(i<=n)
            dp[i] = 1;
        else
            dp[i] = 0;
    double t = min(n-k+1, w);
    for(int i=k-1;i>=0;i--){
        dp[i] = t / w;
        t += dp[i] - dp[i+w];
    }
    printf("%.5f\n", dp[0]);
    return 0;
}
发表于 2022-07-02 09:23:37 回复(0)
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int N,K,W;
    cin>>N>>K>>W;
    // dp[i] 当前持有i点的情况下的答案
    vector<float>dp(N+W+1,0);
    // 持有这些点数时,概率为1
    for(int i=K;i<=N;++i) dp[i] = 1.0;
    // 持有i点时(i=K-1,K-2,...0)分别以1/W的概率可以跳到的有效位置
    // 最远跳W步
    // 用s维持这个概率和,使得时间复杂度由O(W)降为O(1)
    // dp[i-1] = (dp[i]+dp[i+1]+...+dp[i+W-1])/W
    // dp[i] = (dp[i+1]+dp[i+2]+...+dp[i+W])/W 有w-2个交叉项
    double s = min(N-K+1,W);
    for(int i=K-1;i>=0;--i)
    {
        dp[i] = s/W;
        s += dp[i]-dp[i+W];
    }
    cout<<fixed<<setprecision(5)<<dp[0]<<endl;
    return 0;
}

编辑于 2020-05-05 01:01:22 回复(0)
写了个递归的代码,模拟游戏过程,但只通过了40%,LeetCode上通过了86/146,超出了时间限制。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;

/**
 * @Date: 2020-05-02 8:01
 * @version: 1.0
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int K = sc.nextInt();
        int W = sc.nextInt();
        ArrayList<Integer> ai = new ArrayList<>();//保存结束时的点数
        ArrayList<Double> ai2 = new ArrayList<>();//保存相应点数出现的概率
        getWay(K, W, ai,0,ai2,1);
        double c = 0;
        Iterator<Integer> it = ai.iterator();
        Iterator<Double> it2 = ai2.iterator();
        while (it.hasNext()){
            if (it.next()<=N)
                c+=it2.next();
            else
                it2.next();
        }
        System.out.println(String.format("%.5f",c));
    }

    private static void getWay(int k, int m, ArrayList<Integer> ai,int count,ArrayList<Double> ai2,double num) {
        if (count>=k){
            ai.add(count);
            ai2.add(num);
            return;
        }
        for (int i=1;i<=m;i++){
            getWay(k,m,ai,count+i,ai2,num/m);
        }
    }
}
LeetCode官方动态规划解答:
import java.util.Scanner;

/**
 * @Date: 2020-05-02 9:31
 * @version: 1.0
 */
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        int K = sc.nextInt();
        int W = sc.nextInt();
        System.out.println(String.format("%.5f",new21Game(N,K,W)));
    }
    public static double new21Game(int N, int K, int W) {
        double[] dp = new double[N + W + 1];
        // dp[x] = the answer when Alice has x points
        for (int k = K; k <= N; ++k)
            dp[k] = 1.0;

        double S = Math.min(N - K + 1, W);
        // S = dp[k+1] + dp[k+2] + ... + dp[k+W]
        for (int k = K - 1; k >= 0; --k) {
            dp[k] = S / W;
            S += dp[k] - dp[k + W];
        }
        return dp[0];
    }
}

编辑于 2020-05-02 09:37:57 回复(2)
写了个递归的代码,但是只能通过百分之二十,实在找不出原因,大佬们帮忙看看哪里有问题
class Solution:
    def __init__(self):
        self.res = 0
        self.count = 0
    def solution(self, n, k, w):
        def helper(i, u):
            if i >= k:
                self.count += u
                if i <= n:
                    self.res += u
                return
            for j in range(1, w+1):
                helper(i+j, u/w)
        helper(0, 10000)
        ans = self.res/self.count
        print(round(ans, 5))



if __name__ == "__main__":
    n, k, w = map(int, input().split())
    case = Solution()
    case.solution(n,k,w)


编辑于 2020-04-11 17:48:00 回复(0)

/*楼上的输出有问题*/

#include<iostream>
#include<vector>
#include<algorithm>
#include<iomanip>
using namespace std;
int main()
{
    int n,k,w;
    cin>>n>>k>>w;
    vector<float> dp(k+w);
    for(int i=k;i<=n;i++)
        dp[i]=1;
    for(int i=n+1;i<k+w;i++)
        dp[i]=0;
    float temp=min(w,n-k+1);
    for(int i=k-1;i>=0;i--)
    {
        dp[i]=temp/w;
        temp+=dp[i]-dp[i+w];
    }
    cout<<fixed<<setprecision(5)<<dp[0];
}




编辑于 2020-02-12 13:00:55 回复(1)
#include<iostream>
#include<vector>
using namespace std;
double getAns(int N, int K, int W){
    vector<double> dp(N+1,0);
    dp[0] = 1;
    for(int i=0; i<K; i++){
        for(int j=i+1; j<=i+W&&j<=N; j++){
            dp[j] += dp[i]/W;
        }
    }
    double ans = 0;
    for(int i=K; i<=N; i++)
        ans += dp[i];
    return ans;
}
int main(){
    int N, K, W;
    while(cin>>N>>K>>W){
        double ans = getAns(N, K, W);
        ans = int(ans*100000+0.5)/100000.0;
        cout<<ans<<endl;
    }
    return 0;
}

发表于 2019-07-07 09:02:00 回复(0)

招商银行信用卡中心2019秋招IT笔试(AI、开发、测试开发方向)第二批

https://blog.csdn.net/FlushHip/article/details/84138112

发表于 2018-11-19 22:40:19 回复(0)