2016. 4.10 NOI codevs 动态规划练习

1.codevs1040 统计单词个数

1040 统计单词个数

2001年NOIP全国联赛提高组

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 黄金 Gold

题目描述 Description

给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份(1<k<=40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)(管理员注:这里的不能再用指的是位置,不是字母本身。比如thisis可以算做包含2个is)。
单词在给出的一个不超过6个单词的字典中。
要求输出最大的个数。

输入描述 Input Description

第一行为一个正整数(0<n<=5)表示有n组测试数据
每组的第一行有二个正整数(p,k)
p表示字串的行数;
k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有一个正整数s,表示字典中单词个数。(1<=s<=6)
接下来的s行,每行均有一个单词。

输出描述 Output Description

每行一个整数,分别对应每组测试数据的相应结果。

 

样例输入 Sample Input

1
1 3
thisisabookyouareaoh
4
is
a
ok
sab

样例输出 Sample Output

7

数据范围及提示 Data Size & Hint

this/isabookyoua/reaoh

分类标签 Tags 点此展开

划分型DP 动态规划 大陆地区 NOIP全国联赛提高组 2001年

代码:

不知道为什么?把网站的测试数据下到自己电脑上以后,测试全部能通过,可是在线评测不是“运行错误”,就是“超时”。

/*基本思路:预处理一个 g[i][j]表示i--j这个区间内有多少个单词?我是用的
strstr, 函数完成的,寻找字串的位置、
怎么满足题目中要求的“当选用一个单词之后,其第一个字母不能再用,这里的不能再用指的是位置”?
我是设置了head这个标志位,既然这个首字母不能再用了,那么短的单词来充当这个位置,一定比长单词好,所以先把单词字典按照len排序,
DP方程:     f[j][i]=max(f[j][i],f[t][i-1]+g[t+1][j]);
把前j个分为i份的最优值,是通过枚举把前t个分为i-1份,和剩下的部分分为1份来得到的
*/
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LEN 250
#define K 41
int n,p,k,s1;
struct ZD{
    char s[LEN];
    int len;
    bool operator <(const ZD &q)
    const{return len<q.len;}
};
ZD zd[7];
int lenclac,f[LEN][K],g[LEN][LEN];
bool head[LEN];
char clac[LEN];
void input()
{
    memset(head,0,sizeof(head));
    memset(clac,0,sizeof(clac));
    memset(zd,0,sizeof(zd));
    memset(g,0,sizeof(g));
    memset(f,0,sizeof(f));
    scanf("%d%d",&p,&k);
    for(int i=0;i<p;++i)
    scanf("%s",clac+20*i+1);
    lenclac=strlen(clac+1);
    scanf("%d",&s1);
    for(int i=1;i<=s1;++i)
    {
        scanf("%s",zd[i].s+1);
        zd[i].len=strlen(zd[i].s+1);
    }
    clac[0]=‘1‘;
    clac[lenclac+1]=‘\0‘;
    /*如果这里不给clac[0]赋值的话,那么下面的strcpy会出错*/
}
void chuli()
{
    sort(zd+1,zd+s1+1);
    for(int i=1;i<=s1;++i)
    {
        char cpy[LEN];
        strcpy(cpy,clac);
        int p;
        while(1)
        {
            p=strstr(cpy,zd[i].s+1)-cpy;
            if(p<0) break;
            if(head[p])
            {
            for(int j=1;j<=p;++j)
            cpy[j]=‘1‘;
            continue;}/*不加这个赋值是1,会陷入死循环*/
            head[p]=true;
            for(int j=1;j<=p;++j)
            cpy[j]=‘1‘;
            for(int j=p+zd[i].len-1;j<=lenclac;++j)
            {
                g[p][j]++;
                f[j][1]++;
            }
        }
    }
}
void DP()
{
    for(int i=2;i<=k;++i)
      for(int j=i;j<=lenclac;++j)
      {
          for(int t=i-1;t<=j-1;++t)/*t这里必须循环到j-1而不是j,一开始就犯了这个错误,必须保证前j个分成i份才可以,循环到j,那可能是前j个分成了i-1份,*/
          {
              f[j][i]=max(f[j][i],f[t][i-1]+g[t+1][j]);
          }
      }
}
int main()
{

    scanf("%d",&n);
    while(n--)
    {
        input();
        chuli();
        DP();
        printf("%d\n",f[lenclac][k]);
    }
    return 0;
}

/*
把字符串ss[0..len-1]划分为k部分的最优值,需考虑
把前i个字符划分成j个部分的最优值
f(i,j) =Max{f(i-x,j-1)+后x个字符中的单词个数}     (i>=j且x>=1,i-x>=j-1)
即1<=x<i-j
对于区间[ii..jj]中含有的单词个数,逐个统计以s[kk](ii<=kk<=jj)开头的单词即可,
*/
#include <stdio.h>
#define maxlen 210
#define maxk 41
#define maxs 10
int n,p,k,s,f[maxlen][maxk],len;
char ss[maxlen],tt[maxlen],w[maxs][maxlen];
void init(){
    scanf("%d%d",&p,&k);
    len=0;
    for(int i=0;i<p;++i){
        scanf("%s",tt);
        for(int j=0;tt[j];++j){
            ss[len]=tt[j]; ++len;
        }
    }
    ss[len]=‘\0‘;
    scanf("%d",&s);
    for(int i=0;i<s;++i) scanf("%s",w[i]);
    for(int i=0;i<len;++i)
    for(int j=1;j<=k;++j) f[i][j]=0;
}
int calc(int x,int y){    //count of words in ss[x..y]
    int ans=0;
    for(int i=x;i<=y;++i){
        int j,cur;
        for(j=0;j<s;++j){
            for(cur=0;w[j][cur];++cur)
                if(i+cur>y||w[j][cur]!=ss[i+cur]) break;
            if(w[j][cur]==‘\0‘){
                ++ans; break;
            }
        }
    }
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int nn=0;nn<n;++nn){
        init();
        for(int i=1;i<=len;++i) f[i][1]=calc(0,i-1);
        for(int j=2;j<=k;++j){
            for(int i=j;i<=len;++i){
                for(int x=1;x<i-j;++x){
                    int tmp=calc(i-x,i-1);
                    if(f[i][j]<f[i-x][j-1]+tmp)
                        f[i][j]=f[i-x][j-1]+tmp;
                }
            }
        }
        printf("%d\n",f[len][k]);
    }
    return 0;
}

teacher‘s

2. codevs 1163 访问艺术馆--树形DP经典例题

1163 访问艺术馆

时间限制: 1 s

空间限制: 128000 KB

题目等级 : 大师 Master

题目描述 Description

皮尔是一个出了名的盗画者,他经过数月的精心准备,打算到艺术馆盗画。艺术馆的结构,每条走廊要么分叉为二条走廊,要么通向一个展览室。皮尔知道每个展室里藏画的数量,并且他精确地测量了通过每条走廊的时间,由于经验老道,他拿下一副画需要5秒的时间。你的任务是设计一个程序,计算在警察赶来之前(警察到达时皮尔回到了入口也算),他最多能偷到多少幅画。

输入描述 Input Description

第1行是警察赶到得时间,以s为单位。第2行描述了艺术馆得结构,是一串非负整数,成对地出现:每一对得第一个数是走过一条走廊得时间,第2个数是它末端得藏画数量;如果第2个数是0,那么说明这条走廊分叉为两条另外得走廊。数据按照深度优先得次序给出,请看样例

输出描述 Output Description

输出偷到得画得数量

样例输入 Sample Input

60

7 0 8 0 3 1 14 2 10 0 12 4 6 2

样例输出 Sample Output

2

数据范围及提示 Data Size & Hint

s<=600

走廊的数目<=100

题目分析:很明显,这是一棵二叉树,所以我们采用递归建树的方法。

DP方程:因为这是一棵树,所以不是线性循环,使用记忆化搜索是比较容易实现的。

对于每一个点:if这是叶节点,判断能拿到多少画

if这不是叶节点,就把当前的时间平分给左右结点,(从0--tt)循环,统计出最大值

/*首先,根据数据建立二叉树
定义f(tot,k)表示
在剩余时间是tot的情况下,出发去第k个结点为根的子树中,
能得到的画的最大数量。
时间tot的构成:
    到达及离开子树的时间:    2*t[k].v
    分别在左右子树中的时间: x    y
*/
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#define T 601
#define N 201
struct Node{
    int tim,val,child[2];
};
Node node[N];
int f[N][T];
int t,n=0;
void build(int k)
{
    ++n;
    int j=n;
    scanf("%d%d",&node[n].tim,&node[n].val);
    node[n].tim*=2;/*计算上回去的时间,就直接把时间存成2倍*/
    if(node[n].val)
    {
        node[n].child[0]=node[n].child[1]=0;
        return ;
    }
    node[j].child[0]=n+1;
    build(n+1);
    node[j].child[1]=n+1;/*注意这里是node[j],储存在这个递归阶段的父节点,而不是n,因为n是全局变量,所以随时会变化*/
    build(n+1);
}
void input()
{
    scanf("%d",&t);
    int x,y;
    build(1);
}
int DFS(int k,int ti)
{
    int tt=ti;
    if(f[k][tt]>0) return f[k][tt];
    ti-=node[k].tim;/*计算到达该点后当前的剩余时间*/
    if(ti<=0) return 0;
    if(node[k].val)/*如果是叶节点,就偷画*/
    {
        int c=0;
        int l=node[k].val;
        while(ti>=5&&l>=1)/*注意这里不是node[k].val--,因为我们更新的时候,一个叶节点会被访问多次,这次减没了,下次来的时候就不对了*/
        {
            ti-=5;
            l--;//
            c++;
        }
        return f[k][tt]=c;
    }
    for(int i=0;i<=ti;++i)/*如果这不是叶节点,就把时间分为两份,一份去左孩子,一份去右孩子*/
    {
        int ans=0;
        ans+=DFS(node[k].child[0],i);
        ans+=DFS(node[k].child[1],ti-i);
        f[k][tt]=max(f[k][tt],ans);/*循环ti次更新出最大值,这也就是前面说的叶节点多次访问,不能把node[k].val--,否则会陷入死循环,一直return和进入*/
    }
    return f[k][tt];
}
int main()
{
    input();
    printf("%d\n", DFS(1,t));
    return 0;
}

3.NOI 4982:踩方格

4982:踩方格--一个简单但是需要动脑子想方程的题

总时间限制: 
1000ms

内存限制: 
65536kB
描述

有一个方格矩阵,矩阵边界在无穷远处。我们做如下假设:
a.    每走一步时,只能从当前方格移动一格,走到某个相邻的方格上;
b.    走过的格子立即塌陷无法再走第二次;
c.    只能向北、东、西三个方向走;
请问:如果允许在方格矩阵上走n步,共有多少种不同的方案。2种走法只要有一步不一样,即被认为是不同的方案。

输入
允许在方格上行走的步数n(n <= 20)
输出
计算出的方案数量
样例输入
2
样例输出
7
代码+分析:

/*这里采用倒推法:以后遇到没法直接寻找题目,或者题目条件不是很全,一般都是有很简单的方程,仅仅与n有关的方程*/
/*设l[i],r[i],u[i],设为最后一步向左,右,上走到第i个格子的方案数目,那么它的前一步,根据题目中说的“走过的格子立即塌陷无法再走第二次”,可以得出
l[i]=u[i-1]+l[i-1],r[i]=r[i-1]+u[i-1],u[i]=u[i-1]+l[i-1]+r[i-1],(可以看出u[i]=f[i-1]);
 f[i]= u[i]+ l[i]+ r[i];
 =2*(u[i-1]+r[i-1]+l[i-1])+u[i-1](代入上式)
 所以f[i]=2*[i-1]+f[i-2]
*/
#include<cstdio>
long long int f[50];
int n;
int main()
{
    scanf("%d",&n);
    f[1]=3;
    f[2]=7;
    for(int i=3;i<=n;++i)
    f[i]=2*f[i-1]+f[i-2];
    printf("%d",f[n]);
    return 0;
 } 

4.NOI 6252:带通配符的字符串匹配

6252:带通配符的字符串匹配

总时间限制: 
1000ms

内存限制: 
65536kB
描述

通配符是一类键盘字符,当我们不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符。通配符有问号(?)和星号(*)等,其中,“?”可以代替一个字符,而“*”可以代替零个或多个字符。

你的任务是,给出一个带有通配符的字符串和一个不带通配符的字符串,判断他们是否能够匹配。

例如,1?456 可以匹配 12456、13456、1a456,但是却不能够匹配23456、1aa456; 
2*77?8可以匹配 24457798、237708、27798。

输入
输入有两行,每行为一个不超过20个字符的字符串,第一行带通配符,第二行不带通配符
输出
如果两者可以匹配,就输出“matched”,否则输出“not matched”
样例输入
1*456?
11111114567
样例输出
matched
基本思路:
因为是两个字符创匹配的问题,所以定义状态为f[i][j]表示a串的前i个与b串的前j个是否匹配。
然后对a[i]的值进行讨论:

if(a[i]==‘?‘)
f[i][j]=f[i-1][j-1];
else if(a[i]==‘*‘)
f[i][j]=f[i-1][k](0<=k<=j)这里*比较特殊,如果a[i]==‘*‘的话,那么只要f[i-1]与j及其之前的所有取值有一个f[i-1][k]匹配就可以了,因为*可以代表0--j所有的字符。为了减小循环次数,我们可以设一个ok变量来储存着结果
else f[i][j]=f[i-1][j-1]&&(a[i]==b[j]);

值得注意的一点:

注意a的前多项都是*的例子,那么这个时候f[i][0]就是true了,对于这种情况,我们必须考虑到

代码一:

#include<iostream>
using namespace std;
#include<cstdio>
char a[31],b[31],lena,lenb;
#include<cstring>
bool f[31][31];
int main()
{
    scanf("%s%s",a+1,b+1);
    lena=strlen(a+1);
    lenb=strlen(b+1);
    f[0][0]=true;
    int l=1;
    while(a[l++]==‘*‘)
    {
        f[l-1][0]=true;/*考虑前缀*的例子*/
    }
    for(int i=1;i<=lena;++i)
     {
       bool ok=false;/*必须给ok初值是false,否则默认是true,会造成错误*/
       for(int j=1;j<=lenb;++j)
      {
        ok=ok||f[i-1][0]||f[i-1][j];
          if(a[i]==‘?‘)
          f[i][j]=f[i-1][j-1];
          else if(a[i]==‘*‘)
          f[i][j]=ok;
        else f[i][j]=f[i-1][j-1]&&(a[i]==b[j]);
      }
     }
    if(f[lena][lenb]) printf("matched\n");
    else printf("not matched\n");
    return 0;
 } 

代码二(思路是相同的):

#include<iostream>
using namespace std;
#include<cstdio>
#define N 25
#include<cstring>
int lena,lenb,f[N][N];
char a[N],b[N];
int main()
{
    scanf("%s%s",a+1,b+1);
    lena=strlen(a+1);
    lenb=strlen(b+1);
    f[0][0]=true;
    for(int i=1;i<=lena;++i)
    {
        bool ok=f[i-1][0];/*这里是处理前缀*的情况*/
        if(a[i]==‘*‘) f[i][0]=ok;
        for(int j=1;j<=lenb;++j)
        {
            ok=ok||f[i-1][j];/*因为ok本身已经有了f[i-1][0],所以不必再加了*/
            if(a[i]==‘?‘)
            f[i][j]=f[i-1][j-1];
            else if(a[i]==‘*‘)
            f[i][j]=ok;
            else f[i][j]=f[i-1][j-1]&&(a[i]==b[j]);
        }
    }
    if(f[lena][lenb]) printf("matched\n");
    else printf("not matched\n");
    return 0;
}

5.洛谷P1282 多米诺骨牌

P1282 多米诺骨牌--01背包法

  • 标签动态规划
  • 难度提高+/省选-
  • 通过/提交282/964

题目描述

多米诺骨牌有上下2个方块组成,每个方块中有1~6个点。现有排成行的

上方块中点数之和记为S1,下方块中点数之和记为S2,它们的差为|S1-S2|。例如在图8-1中,S1=6+1+1+1=9,S2=1+5+3+2=11,|S1-S2|=2。每个多米诺骨牌可以旋转180°,使得上下两个方块互换位置。

编程用最少的旋转次数使多米诺骨牌上下2行点数之差达到最小。

对于图中的例子,只要将最后一个多米诺骨牌旋转180°,可使上下2行点数之差为0。

输入输出格式

输入格式:

输入文件的第一行是一个正整数n(1≤n≤1000),表示多米诺骨牌数。接下来的n行表示n个多米诺骨牌的点数。每行有两个用空格隔开的正整数,表示多米诺骨牌上下方块中的点数a和b,且1≤a,b≤6。

输出格式:

输出文件仅一行,包含一个整数。表示求得的最小旋转次数。

输入输出样例

输入样例#1:

4
6 1
1 5
1 3
1 2

输出样例#1:

1

问题分析:

很明显,对于当前骨牌只有翻与不翻两种选择,就像是01背包取物品的时候的取与不取是相通的,那么我们就可以尝试用01背包解决,如果这个牌不翻,会是什么状态?如果翻了是什么状态?选择的标准就是犯的次数最少。

代码一:

未压缩空间版:

#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#define INF 1010
#define Q 2000
int n,N,w[INF];
int f[INF][INF*10];
void input()
{
    int a,b;
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        scanf("%d%d",&a,&b);
        w[i]=a-b;
    }
}
void DP()
{
    N=5*n;/*进行平移的数,防止数组越界,5*n就是最大的差值了*/
    memset(f,127,sizeof(f));
    f[1][w[1]+N]=0;/*差值全部定义成a-b,那么对于前i张牌的状态,我们是可以直接得出的,这也是DP的边界*/
    f[1][-w[1]+N]=1;/**/
    for(int i=2;i<=n;++i)
      for(int j=10*n;j>=0;--j)/*类似有01背包*/
      {
          if(j+w[i]>=0&&j+w[i]<=10*n)/*注意要下越界和上越界都判断,因为w[i]的正负是不一定的*/
          f[i][j]=min(f[i][j],f[i-1][j+w[i]]+1);/*设t是前i-1个牌的某个翻法的差值推到f[i][j]这个状态,如果不翻牌,那么j=t+w[i],可以倒推出t的两个值,对应着翻牌与不翻牌*/
          if(j-w[i]>=0&&j-w[i]<=10*n)
          f[i][j]=min(f[i][j],f[i-1][j-w[i]]);
      }
    if(f[n][5*n]<Q) printf("%d\n",f[n][5*n]);/*Q是我估计的最大翻转次数,这个用来判断当前的差值能不能通过翻牌得到,如果不能得到,一定比Q大,那么再向5*n的两侧找*/
    else {
        for(int i=5*n-1,j=5*n+1;j<=10*n&&i>=1;++j,--i)
        {
            if((f[n][i]<Q||f[n][j]<Q))
            {
                printf("%d\n",min(f[n][i],f[n][j]));
                return ;
            }
        }
    }

}
int main()
{
    input();
    DP();
    return 0;
}

分析:能否使用滚动数组,进行压缩空间?
答案是否定的。
让我们仔细看一下这个DP方程:
if(j+w[i]>=0&&j+w[i]<=10*n)
	  	f[i][j]=min(f[i][j],f[i-1][j+w[i]]+1);
if(j-w[i]>=0&&j-w[i]<=10*n)
	  	f[i][j]=min(f[i][j],f[i-1][j-w[i]]);
它的确符合只与上一层有关,但是遇上一层哪一个有关,就与01背包不同了,因为01背包倒序循环,更新只与比二维j小的数有关,但是这个方程明显也可能与比二维j大的数有关,所以不能用。

  

时间: 2024-11-04 20:55:08

2016. 4.10 NOI codevs 动态规划练习的相关文章

2016.4.9 NOI codevs动态规划专练

1.NOI 最大子矩阵 1:最大子矩阵 总时间限制:  1000ms 内存限制:  65536kB 描述 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的矩阵 0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -2 的最大子矩阵是 9 2-4 1-1 8 这个子矩阵的大小是15. 输入 输入是一个N * N的矩阵.输入的第一行给出N (0 < N <= 100).再后面的若干行中,依次(首先从

【读书笔记】2016.12.10 《构建高性能Web站点》

本文地址 分享提纲: 1. 概述 2. 知识点 3. 待整理点 4. 参考文档 1. 概述 1.1)[该书信息] <构建高性能Web站点>: -- 百度百科 -- 本书目录: 第1章 绪论 1.1 等待的真相 1.2 瓶颈在哪里 1.3 增加带宽 1.4 减少网页中的HTTP请求 1.5 加快服务器脚本计算速度 1.6 使用动态内容缓存 1.7 使用数据缓存 1.8 将动态内容静态化 1.9 更换Web服务器软件 1.10 页面组件分离 1.11 合理部署服务器 1.12 使用负载均衡 1.1

武汉北大青鸟解读2016年10大IT热门岗位

武汉北大青鸟解读2016年10大IT热门岗位 2016年1月5日 13:37 北大青鸟 这是IT从业者的辉煌时代,IT行业的失业率正处在历史的低点,而且有的岗位——例如网络和安全工程师以及软件开发人员——甚至出现徘徊在1%的失业率.最新调查显示,81%的IT领导者表示很难找到IT人才.即使你不是安全专家也不是软件开发人员,依然也有大量的就业机会.下面武汉北大青鸟徐东校区为你介绍2016年10个热门的IT技能,这些技能是由在IT人力咨询公司Mondo,自由职业者和签约市场Upwork,以及IT教育

2016年10个最热门 IT 职业岗位

北京尚学堂提供 IT时代已经开启.下面就是2016年需求最高的这10项技术. 这是IT从业者的辉煌时代.IT行业的失业率正处在历史的低点,而且有的岗位——例如网络和安全工程师以及软件开发人员——甚至出现徘徊在1%的失业率.根据最近的TEKsystems调查,81%的IT领导者表示很难找到IT人才. 即使你不是安全专家也不是软件开发人员,依然也有大量的就业机会.下面我们要介绍2016年10个热门的IT技能,这些技能是由在IT人力咨询公司Mondo,自由职业者和签约市场Upwork,以及IT教育和培

2016年10月数据库流行度排行榜

DB-Engines Ranking发布了2016年10月最新数据库流行度排行: db趋势

Murano Weekly Meeting 2016.05.10

Meeting time: 2016.May.10 1:00~2:00 Chairperson:  Serg Melikyan, from Mirantis Meeting summary: 1. murano contributors rules Six usage rule: use it only when really necessary (for example if existing code will now work in Py3 at all. If it is a matte

海豚驾考2016年10月8日系统升级公告

海豚驾考2016年10月8日系统升级公告 功能概述: 1.学员报名支付成功后 2.相关人员登陆后台为学员指派一个教练(后面系统完善后,由系统自动指派) 3.在后台[教练列表页]可以查看所有教练各个阶段下的学员人数 4.教练在微信端个人中心页,进入[我的学员]列表页,可以查看各个阶段下的学员 5.教练根据学员的阶段,安排学员学习(包括准备资料.科目一.科目二.... 直到拿本) 6.教练可以在微信上给学员约车(以及取消预约).设置学员的进度 1.微信 - 教练端个人中心页升级(查看我的学员 ->

2016.6.10 考试总结

汽艇(Boat.cpp/c/pas) [问题描述] 有 n 个人要去坐 1 汽艇,每个人单独坐汽艇的快乐程度是 Ci,每多一个人,他的快乐程度会减去 Di,请求出使快乐程度之和达到最大的方案.(假设汽艇的容量足够大). [输入格式] 输入文件共有 3 行: 第1 行是一个整数 n: 第2 行有n 个整数,依次表示每个人单独坐汽艇的快乐程度 Ci(1<=Ci<=10000): 第3 行有n 个整数,依次表示每多 1 人,每个人快乐程度的下降值 Di(1<=Di<=10). [输出格式

2016年10月10日--穷举、迭代、while循环

穷举 将所有可能性全部全部走一遍,使用IF筛选出满足的情况 练习: 1.单位给发了一张150元购物卡, 拿着到超市买三类洗化用品. 洗发水15元,香皂2元,牙刷5元. 求刚好花完150元,有多少种买法, 没种买法都是各买几样? int i = 0; int j = 0; for (int x = 0; x <= 10; x++) { for (int y = 0; y <= 30; y++) { for (int z = 0; z <= 75; z++) { j++; if (x * 1