注册 登录
编程论坛 C++教室

[全民编程]76道高难度C++练习题.含NOI竞赛题.欢迎挑战

野比 发布于 2007-06-16 11:57, 48939 次点击

偶然从朋友那里搞到的, 名字是<<C++入门题>>
题目都相当的经典. 还有不少是NOI的考试题.
1 - 20题作为热身(见2楼), 越往后越难, 完整版(76道)请到1楼楼底下载.

请解决问题后, 不要吝惜你的才华, 把解题方法跟贴, 大家共同学习提高.

统计时间: 2007-10-10 19:29[/quote]

目前已完成题目(按发帖时间先后排序)

题号 完成人 楼层
---------------------------------------------
2 百年不亮 3
5 HCL 4
20 aipb2007 5,6
17 游乐园/aipb2007 18/20
6 HCL 26,27
16 jiaju111 33 讨论完成, 未编程
11 aipb2007 46
75 HJin 48 不符题干, 参考
49 HJin 49
48 HJin 61
10 HJin 62 * 218楼(blueboy82006),236楼(远去的列车)修改
13 HJin 63
17 HJin 65
1 HJin 67
3 tianma8778 69 有缺陷, 供参考
24 HJin 71
1 kai 77 另一种解法
2 kai 79 数字电路分析法
4 HJin 80
3 kai 81 # With analysis
19 HJin 83
3 laigaoat2005 69
37 HJin 103 162楼补充说明(smartwind)
67 HJin 104
74 HJin 105
4 wfpb 107 * + (kai指出, 见117楼)
3 smartwind 108 *
9 smartwind 109 *
8 wfpb 110 *
3 zkkpkk 111 *
12 wfpb 112 *
75 smartwind 113 *
37 weishj 114 *
41 zkkpkk 115 * 166楼改进(smartwind)
6 zkkpkk 118 * 130楼补充蛇形填数
65 weishj 124 *
14 huozoo 126 @ 正确
7 zkkpkk 137 *
76 HJin 138 *
4 天空の城 140 *
58 HJin 141 *
9 zkkpkk 142 *
13 zkkpkk 144 *
57 HJin 147 *
53 HJin 148 *
22 HJin 149 *
43 zkkpkk 150 *
21 HJin 152 *
31 smartwind 160 * 164楼补充(HJin) 165楼补充(smartwind)
34 smartwind 161 # 分析
45 smartwind 172 *
2 zhchchqihu 194,193 * 2种方法
3 freshman42 196 *
? blueboy82006 208 *
2 卧龙孔明 209,210 * 2种方法
1 hkice 211 *
5 hkice 212 *
3 miaomiao0403 214 *
10 ml232528 215 * 指出62楼10题错误
55 远去的列车 220 *
48 远去的列车 222 *
14 huozoo 223 * 解答者本人不确定
2,3 xjlsgcjdtc 228,229 *
3 qq598369 230 *
3 远去的列车 232 *
3 曦木 233 *
6 远去的列车 234 *
7 海子星竹 239 *
3 且行且珍惜 240 *


注:
* 未测试 (Not tested)
@ 已测试 (Tested)
+ Bug
# 无源代码 (No code)

完整版(76道)下载[attach]22592[/attach]


[此贴子已经被作者于2007-10-10 19:29:50编辑过]

288 回复
#2
野比2007-06-16 11:58

No.1 - 20 热身题

1. 给定等式 A B C D E 其中每个字母代表一个数字,且不同数字对应不
D F G 同字母。编程求出这些数字并且打出这个数字的
+ D F G 算术计算竖式。

───────

X Y Z D E

2. A、B、C、D、E五名学生有可能参加计算机竞赛,根据下列条件判断哪些
人参加了竞赛:

(1)A参加时,B也参加;

(2)B和C只有一个人参加;

(3)C和D或者都参加,或者都不参加;

(4)D和E中至少有一个人参加;

(5)如果E参加,那么A和D也都参加。

3. 打印一个 N*N 的方阵,N为每边 N=15 打印出下面图形
字符的个数(3<N<20), 要求最 TTTTTTTTTTTTTTT
外一层为"T", 第二层为"J", 从第三层 TJJJJJJJJJJJJJT
起每层依次打印数字 1,2,3,... TJ11111111111JT
(右图以N为15为例) TJ12222222221JT
TJ12333333321JT
TJ12344444321JT
TJ12345554321JT
TJ12345654321JT
TJ12345554321JT
TJ12344444321JT
TJ12333333321JT
TJ12222222221JT
TJ11111111111JT
TJJJJJJJJJJJJJT
TTTTTTTTTTTTTTT

4. 在N行N列的数阵中, 数K(1〈=K〈=N)在每行和每列中出现且仅
出现一次,这样的数阵叫N阶拉丁方阵。例如下图就是一个五阶拉丁方阵。
编一程序,从键盘输入N值后,打印出所有不同的N阶拉丁方阵,并统计个数。

1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4


5. 输入一个十进数,将其转换成 N 进制数(0<N<=16)。
6. 矩阵中填数. 当给出 N*N 的矩阵,要求用程序填入下列形式的数:

① 倒填,例如N=5 ② 蛇形填数 ③ 回转填数

┌─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┐ ┌─┬─┬─┬─┬─┐
│25│24│23│22│21│ │ 1│ 3│ 4│10│11│ │ 1│16│15│14│13│
├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤
│20│19│18│17│16│ │ 2│ 5│ 9│12│19│ │ 2│17│24│23│12│
├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤
│15│14│13│12│11│ │ 6│ 8│13│18│20│ │ 3│18│25│22│11│
├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤
│10│ 9│ 8│ 7│ 6│ │ 7│14│17│21│24│ │ 4│19│20│21│10│
├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤ ├─┼─┼─┼─┼─┤
│ 5│ 4│ 3│ 2│ 1│ │15│16│22│23│25│ │ 5│ 6│ 7│ 8│ 9│
└─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┘ └─┴─┴─┴─┴─┘


7. 读入一行文本,包含若干个单词(以空格间隔,%结尾)。将其中以 A 开头的
单词与以 N 结尾的单词,用头尾交换的办法予以置换。

8. 输入两个正整数X,Y,将X,Y化为二进制数,然后将这两个二进制数作二进
制加法运算,再将结果化为十进制数输出。

9. 四人玩火柴棍游戏,每一次都是三个人赢,一个人输。输的人要按赢者手中的火柴
数进行赔偿,即赢者手中有多少根火柴棍,输者就赔偿多少根。现知道玩过四次后,
每人恰好输过一次, 而且每人手中都正好有16根火柴。问此四人做游戏前手中各有
多少根火柴? 编程解决此问题。

10. 如图1所示,编写程序计算 ┎┰┰┰┰┰┰┰┰┰┒
大大小小正方形共有多少?当最小 ┠╂╂╂╂╂╂╂╂╂┨
正方行边长为1时,它们的总面积 ┠╂╂╂╂╂╂╂╂╂┨
共为多少? ┠╂╂╂╂╂╂╂╂╂┨
┠╂╂╂╂╂╂╂╂╂┨
┠╂╂╂╂╂╂╂╂╂┨
┠╂╂╂╂╂╂╂╂╂┨
┠╂╂╂╂╂╂╂╂╂┨
┠╂╂╂╂╂╂╂╂╂┨
┠╂╂╂╂╂╂╂╂╂┨
┖┸┸┸┸┸┸┸┸┸┚
11. 巧排数字。将1、2、...、20这20个数排成一排,使得相邻的两个数之
和为一个素数,且首尾两数字之和也为一个素数。编程打印出所有的排法。

12. 下图是一个集装箱仓库,阴影部分表示有集装箱存放不能通过,无阴影处为临时通
道。当有人要从入口处到达出口处时,必须寻找可通过路线,请你找出可完成这个过程
的最方便(即用最短路线)到达出口处的路径。

┎┰┰┰入口┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┰┒
┠╂╂╂──╂╂╂╂┸┸╂┸┸╂┸┸╂┸┸╂╂╂╂┸┸╂╂╂┨
┠╂╂╂──╂┸┸╂──╂┰┰╂┰┰╂──╂╂╂╂──╂╂╂┨
┠╂╂╂──╂┰┰╂┰┰╂╂╂╂╂╂╂──╂┸┸╂──╂╂╂┨
┠╂╂╂──╂╂╂╂╂╂╂╂╂╂╂╂╂┰┰╂┰┰╂┰┰╂╂╂┨
┠╂╂╂──╂┸┸╂┸┸╂┸┸╂┸┸╂┸┸╂┸┸╂┸┸╂╂╂┨
┠╂╂╂──╂┰┰╂┰┰╂┰┰╂──╂┰┰╂──╂┰┰╂╂╂┨
┠╂╂╂──╂╂╂╂╂╂╂╂╂╂──╂╂╂╂──╂╂╂╂╂╂┨
┠╂╂╂──╂╂╂╂┸┸╂┸┸╂──╂╂╂╂──╂┸┸╂╂╂┨
┠╂╂╂──╂╂╂╂┰┰╂┰┰╂┰┰╂╂╂╂┰┰╂──╂╂╂┨
┖┸┸┸──┸┸┸┸┸┸┸┸┸┸┸┸┸┸┸┸┸┸┸出口┸┸┸┚


13. 有N个硬币(N为偶数)正面朝上排成一排,每次将 N-1 个硬币翻过来放在原位
置, 不断地重复上述过程,直到最后全部硬币翻成反面朝上为止。编程让计算机把
翻币的最简过程及翻币次数打印出来(用*代表正面,O 代表反面)。

14. 有黑白棋子各有N个(分别用*和O代替),按下图方式排列

***...***OOO...OOO

N个黑棋 N个白棋

允许将相邻两个棋子互换位置,最后使队形成黑白交替排列,试编程实现该操作。

15. 已知6个城市,用c[i,j]表示从i城市到城市j是否有单向的直达汽车

(1=<i〈=6,1〈=j〈=6), c[i,j]=1 表示城市i到城市j有单向直达汽
车; 否则 c[i,j]=0. 试编制程序,对于给出的城市代号i,打印出从该城市出
发乘车(包括转车)可以到达的所有城市。
16. 设有8枚硬币a,b,c,d,e,f,g,h,其中有一枚硬币是伪造的。
真伪硬币的区别仅是重量不同,可能重,可能轻。今要求以天平为工具,用最少的
比较次数挑出伪造硬币,并鉴定它是重还是轻。

17. 编写一个程序,当输入不超过60个字符组成的英文文字时,计算机将这个句子
中的字母按英文字典字母顺序重新排列,排列后的单词的长度要与原始句子中的长度
相同。例如:

输入:

THE PRICE OFBREAD IS ¥1 25 PER POUND

输出:

ABC DDEEE EFHIINO OP ¥1 25 PPR RRSTU

并且要求只对A到Z的字母重新排列,其它字符保持原来的状态。

18. 在一线性七个格位置的图上有两种不同颜色的棋子A,B. 排列如下图所示,中间
格的位置为空。

┎─┰─┰─┰─┰─┰─┰─┒
┃A┃A┃A┃ ┃B┃B┃B┃
┖─┸─┸─┸─┸─┸─┸─┚

要求将A,B的现行位置交换,形成下图中的排列:

┎─┰─┰─┰─┰─┰─┰─┒
┃B┃B┃B┃ ┃A┃A┃A┃
┖─┸─┸─┸─┸─┸─┸─┚

移动棋子的条件:

(1) 每个格中只准放一个棋子。
(2) 任意一个棋子均可移动一格放入空格内。
(3) 一方的棋子均可跳过另一方的一个棋子进入空格。
(4) 任何棋子不得跳跃两个或两个以上棋子(无论颜色同异)
(5) 任何一个颜色棋子只能向前跳,不准向后跳。

编程完成有关的移动,并且完成具有2N+1个格子的情形. 其中两种颜色各有
N个棋子,且中间为空格.

19. (背包问题) 有 N 件物品 d1,......dN,每件物品重量为 W1,..., WN
(Wi > 0), 每件物品价值为 V1,......VN (Vi>0)。用这N件物品的某个子集
填空背包,使得所取物品的总重量<=TOTAL,并设法使得背包中物品的价值尽可
能高。

20. (N皇后) 在国际象棋的棋盘上放置N个皇后,使其不能互相攻击,即任意
两个皇后不能处在棋盘的同一行,同一列,同一斜线上,试问共有多少种摆法?
21. 请设计一个程序,由计算机把1.. ̄.8的八个自然数填入图中,使得横、
竖、对角任何两个相邻的小方格中的两个数是不连续的。(下图右侧的 4 个图
为禁止的情形).

┌─┐ ┌─┐ ┌─┐
│ │ │4│ │8│
┌─┼─┼─┐ └─┼─┐ ┌─┼─┘
│ │ │ │ │5│ │7│
├─┼─┼─┤ └─┘ └─┘
│ │ │ │ ┌─┐
└─┼─┼─┘ │6│ ┌─┬─┐
│ │ ├─┤ │1│2│
└─┘ │7│ └─┴─┘
└─┘


[此贴子已经被作者于2007-6-16 16:32:25编辑过]

#3
野比2007-06-16 12:03

将百年兄对第2题的解答搬到这里来

2. A、B、C、D、E五名学生有可能参加计算机竞赛,根据下列条件判断哪些
人参加了竞赛:

(1)A参加时,B也参加;

(2)B和C只有一个人参加;

(3)C和D或者都参加,或者都不参加;

(4)D和E中至少有一个人参加;

(5)如果E参加,那么A和D也都参加。

___________________________________________________________________

答案:

#include<stdio.h>
int main()
{
char name[]={'A','B','C','D','E'};
int i,value[5];

for(value[0]=0;value[0]<2;value[0]++)
for(value[1]=0;value[1]<2;value[1]++)
for(value[2]=0;value[2]<2;value[2]++)
for(value[3]=0;value[3]<2;value[3]++)
for(value[4]=0;value[4]<2;value[4]++)
{
if((value[1]>=value[0])
&&(value[1]+value[2]==1)
&&value[2]==value[3]
&&(value[3]+value[4])
&&(!value[4]||(value[4]&&value[0]&&value[3])))
for(i=0;i<5;i++)
if(value[i])
printf("%c参加\t",name[i]);
else
printf("%c不参加\t",name[i]);
}
return 0;

}

结果:

A不参加 B不参加 C参加 D参加 E不参加

#4
HCL2007-06-16 13:00

#include <iostream>
#include <stack>

using namespace std;

int main()
{
char digit[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

cout <<"输入待转换整数: ";
int number;
cin >>number;
cout <<endl;

cout <<"转换成多少进制? ";
int base;
cin >>base;
cout <<endl;

stack<char> stk;
char remain;
while (number!=0)
{
remain = digit[number%base];
stk.push(remain);
number /= base;
}

cout <<"结果: ";
while(!stk.empty())
{
cout <<stk.top();
stk.pop();
}
cout <<endl;
return 0;
}


第五题的,望指点!

#5
aipb20072007-06-16 13:05

辛苦了,我也冒个泡:
N皇后:

版本1:

[CODE]
//file : queens.h
#ifndef QUEENS_H
#define QUEENS_H
const int max_size = 24;
class queens{
public:
//constructor
queens(int size);

//main function
void solution(); //recursive function for backtracking
//times of solutions
static unsigned int times_of_solution;
protected:
//member functions
void print() const; //print the solution
void insert(int col); //add a queen the posn
void remove(int col); //delete a queen at row-1
bool isSolved() const; //return true if all queens at right posn
bool isUnguarded(int col) const; //return true if the posn is guarded by a queen
private:
//data members
int row;
int board_size;
bool chessboard[max_size][max_size];
};
#endif[/CODE]

[CODE]
//file : queens.cpp
#include "queens.h"
#include <iostream>
queens::queens(int size){
board_size = size;
row = 0; //no queen on chess board
for (int i = 0;i < board_size;++i)
for (int j =0;j < board_size;++j)
chessboard[i][j] = false;
}
bool queens::isSolved() const{
return row == board_size;
}
bool queens::isUnguarded(int col) const{
bool isOk = true;
//at current column
for (int i = 0;isOk && i < row;++i)
isOk = !chessboard[i][col];
//at left upper diagonal
for (int i = 1;isOk && row-i >= 0 && col-i >= 0;++i)
isOk = !chessboard[row-i][col-i];
//at right upper diagonal
for (int i = 1;isOk && row-i >= 0 && col+i < board_size;++i)
isOk = !chessboard[row-i][col+i];
return isOk;
}
void queens::insert(int col){
chessboard[row++][col] = true;
}
void queens::remove(int col){
chessboard[--row][col] = false;
}
void queens::print() const{
for (int i = 0;i < board_size;++i){
for (int j = 0;j < board_size;++j)
std::cout << chessboard[i][j] << " ";
std::cout << std::endl;
}
++times_of_solution;
std::cout << "**************************************" << std::endl;
}
void queens::solution(){
if (isSolved())
print();
else
for (int col = 0;col < board_size;++col)
if (isUnguarded(col)){
insert(col);
//for backtracking
solution();
remove(col);
}
}[/CODE]


//file : main.cpp
#include "queens.h"
#include <iostream>
#include <ctime>
using namespace std;

unsigned int queens::times_of_solution = 0;
int main(){
int size;
cin >> size;
while (size < 1 || size > max_size){
cout << "the queen must between 1 ------ " << max_size << endl;
cin >> size;
}
queens puzzle(size);

////////////////////////////////////////////
clock_t start,finish;
start = clock();
////////////////////////////////////////////

puzzle.solution();
cout << "number of solutions ------ " << queens::times_of_solution << endl;

////////////////////////////////////////////
finish = clock();
double time = (double) (finish - start) / CLOCKS_PER_SEC;
cout << "time used ------ " << time << endl;
////////////////////////////////////////////
}

[此贴子已经被作者于2007-6-16 13:12:08编辑过]

#6
aipb20072007-06-16 13:07

版本2 : 无迭代改进版本:


[CODE]
//file : queens.h
#pragma once
const int max_board_size = 24;
class queens{
public:
//constructor
queens(int size);

//main function
void solution(); //recursive function for backtracking
//times of solutions
static unsigned int times_of_solution;
protected:
//member functions
void print() const; //print the solution
void insert(int col); //add a queen the posn
void remove(int col); //delete a queen at row-1
bool isSolved() const; //return true if all queens at right posn
bool isUnguarded(int col) const; //return true if the posn is guarded by a queen
private:
//make bool array for the chessboard
bool col_free[max_board_size];
bool upward_free[2*(max_board_size-1)];
bool downward_free[2*(max_board_size-1)];
int queen_in_rows[max_board_size]; //store the column of queens at each row
//data members
int row;
int board_size;
};[/CODE]

[CODE]
//file : queens.cpp
#include "queens.h"
#include <iostream>
queens::queens(int size){
board_size = size;
row = 0;
//set all columns free
for (int i = 0;i < board_size;++i)
col_free[i] = true;
//set all upward diagonals free
for (int i = 0;i < 2*(board_size-1);++i)
upward_free[i] = true;
//set all downward diagonals free
for (int i = 0;i < 2*(board_size-1);++i)
downward_free[i] = true;
}
bool queens::isSolved() const{
return row == board_size;
}
bool queens::isUnguarded(int col) const{
return col_free[col] && upward_free[row+col]
&& downward_free[row-col+board_size-1];
}
void queens::insert(int col){
queen_in_rows[row] = col;
//set the column & diagonal which is guarded by queen to false
col_free[col] = false;
upward_free[row+col] = false;
downward_free[row-col+board_size-1] = false;
++row;
}
void queens::remove(int col){
//remove a queen at previous row
--row; //back to previous row
//set the column & diagonal which is guarded by queen to true
col_free[col] = true;
upward_free[row+col] = true;
downward_free[row-col+board_size-1] = true;
}
void queens::print() const{
for (int i = 0;i < board_size;++i){
for (int j = 0;j < board_size;++j)
std::cout << (j == queen_in_rows[i] ? "1 " : "0 ");
std::cout << std::endl;
}
std::cout << "---------------------------------" << std::endl;
++times_of_solution;
}
void queens::solution(){
if (isSolved())
print();
else
for (int col = 0;col < board_size;++col)
if (isUnguarded(col)){
insert(col);
//the steps for backtracking
solution();
remove(col);
}
}[/CODE]


//file : main.cpp
#include "queens.h"
#include <iostream>
#include <ctime>
using namespace std;

unsigned int queens::times_of_solution = 0;
int main(){
int size;
cin >> size;
while (size < 4 || size > max_board_size){
cout << "the queen must between 4 ------ " << max_board_size << endl;
cin >> size;
}
queens puzzle(size);

////////////////////////////////////////////
clock_t start,finish;
start = clock();
////////////////////////////////////////////

puzzle.solution();
cout << "number of solutions ------ " << queens::times_of_solution << endl;

////////////////////////////////////////////
finish = clock();
double time = (double) (finish - start) / CLOCKS_PER_SEC;
cout << "time used ------ " << time << endl;
////////////////////////////////////////////
}


[此贴子已经被作者于2007-6-16 13:10:49编辑过]

#7
野比2007-06-16 13:34
仔细研究中
#8
野比2007-06-16 13:46
以下是引用HCL在2007-6-16 13:00:49的发言:

#include <iostream>

...第五题的,望指点!

第五题用堆栈的话就有些限制了吧? 遇到堆栈很小的情况.
如果要考虑负数的话就更难了..象2,8,16等进制都是用补码表示的...啊..好难啊...

[此贴子已经被作者于2007-6-16 14:27:53编辑过]

#9
百年不亮2007-06-16 15:46

第2题分析:

首先要设置逻辑变量。value[i]==1时表示第i(i=0~4依次表示A,B,C,D,E五人)个人参加,为0则不参加。

然后写出逻辑函数。将下面的逻辑关系写成函数形式:
(1)A参加时,B也参加;value[1]>=value[0]
(2)B和C只有一个人参加;value[1]+value[2]==1
(3)C和D或者都参加,或者都不参加;value[2]==value[3]
(4)D和E中至少有一个人参加;(value[3]+value[4])
(5)如果E参加,那么A和D也都参加。(!value[4]||(value[4]&&value[0]&&value[3]))
表示为Y=(value[1]>=value[0])&&(value[1]+value[2]==1)&&value[2]==value[3]&&(value[3]+value[4])&&(!value[4]||(value[4]&&value[0]&&value[3])))

最后穷举法把所有的组合算出来,将Y==1时的情况输出。

#10
野比2007-06-16 16:03
哦, 谢谢百年兄指点!
#11
xslff2007-06-16 17:39
晕,不会C啊,Java编的行不?
#12
xslff2007-06-16 17:50
请问一下,你们编C都用的什么编译器啊?方便的话,可以传我一个么?
#13
野比2007-06-16 18:02
我用TC++, 至于用Java行不行... 没人规定这个C++练习就必须用C++...(^^!)
主要目的是练习编程技巧, 当然要选用自己擅长的语言咯..
何况习题里面好多NOI的题, NOI可是PASCAL的天下啊...
#14
xslff2007-06-16 18:04
呵呵,那我就献献丑啦!
#15
yuyunliuhen2007-06-16 18:04

学JAVA肯定用过EC的了,那个现在可以编译C++程序的啊,加个支持的插件就行了。

[此贴子已经被作者于2007-6-16 19:29:48编辑过]

#16
ggrrrman662007-06-16 19:30
第4楼的程序我怎么不能 编译
用turbo c 显示有很多错误
#17
野比2007-06-16 20:25
以下是引用ggrrrman66在2007-6-16 19:30:50的发言:
第4楼的程序我怎么不能 编译
用turbo c 显示有很多错误

第4楼的程序可以运行... VC++ .NET 2005下编译OK
关键是...那个是C++写的, 老大, 拿TC当然有错了.
你可以用TC++3.0编译看看

#18
游乐园2007-06-17 09:20

很久没来了,现在C++板块弄的蛮不错的...大家继续加油. 路过顺便挑个简单的做做 呵呵

-----------------------------------------------------------------------------------------------------
17. 编写一个程序,当输入不超过60个字符组成的英文文字时,计算机将这个句子
中的字母按英文字典字母顺序重新排列,排列后的单词的长度要与原始句子中的长度
相同。例如:

输入:

THE PRICE OFBREAD IS ¥1 25 PER POUND

输出:

ABC DDEEE EFHIINO OP ¥1 25 PPR RRSTU

并且要求只对A到Z的字母重新排列,其它字符保持原来的状态。


程序代码:

#include<iostream>
#include<string>
#include<cctype>
#include<algorithm>
using namespace std;


int main()
{
string str,s;
int num[60]={0};
int j=1;
getline(cin,str);
for(int i=0; i<str.size(); i++) //把字母字符存到s中
{
  if(isalpha(str[i])) s+=str[i];
  else
  {
   num[j++]=i; //记录非字母字符的位置
      num[0]++; //记录非字母字符的个数
  }
}


sort(s.begin(),s.end()); //排序A~Z或a~z


    if(s.size()!=str.size())
  for(j=1; j<=num[0]; ++j)
   s.insert(num[j],str.substr(num[j],1)); //调整字符串


cout<<endl<<s<<endl;


return 0;
}

#19
aipb20072007-06-17 09:52
以下是引用游乐园在2007-6-17 9:20:18的发言:

很久没来了,现在C++板块弄的蛮不错的...大家继续加油. 路过顺便挑个简单的做做 呵呵

-------------------------------------------------------------------------------------------------

游乐园大哥,很久不来在做什么?呵呵~难得看到你啊!多来耍哈嘛!

#20
aipb20072007-06-17 10:20
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main(){
string input = "",letters = "";
char ch;

while ((ch = getchar()) != '\n'){
if(isalpha(ch))
letters += ch;
input += ch;
}
sort(letters.begin(),letters.end());

for (int i = 0,j = 0;i < input.size();++i){
if (!isalpha(input[i]))
cout << input[i];
else
cout << letters[j++];
}
system("pause");
}
也是17题!
嘿嘿

[此贴子已经被作者于2007-6-17 10:38:17编辑过]

#21
HCL2007-06-17 10:32

第五题那个我是用VC6.0写的,对于正整数都可以,没有考虑其他的!

#22
HCL2007-06-17 10:33
希望此贴可以长期存在,并把已经完成的题放在楼顶作个标记嘛~谢谢!
#23
aipb20072007-06-17 10:42
放了!呵呵~~~~~~~~
#24
simonray2007-06-17 11:08

新手...有点看不懂.

#25
aipb20072007-06-17 11:19
大家讨论下16题最少称几次啊?
------------------------------------------------------------------

16. 设有8枚硬币a,b,c,d,e,f,g,h,其中有一枚硬币是伪造的。
真伪硬币的区别仅是重量不同,可能重,可能轻。今要求以天平为工具,用最少的
比较次数挑出伪造硬币,并鉴定它是重还是轻。

------------------------------------------------------------------
我用4次似乎多了!
#26
HCL2007-06-17 12:55

仿佛是第六题吧!帮忙看一下,如果有冗余的地方还望多提点一下
希望看起不会太痛苦! --VC6.0
#include <iostream>
#include <iomanip>
#include <vector>

using namespace std;

int main()
{
cout <<"Enter a number : ";
int number;
cin >>number;
int total = number * number;
int i = 0;
int j = 0;
//(1):
for (i = 0 ; i < number ; ++i)
{
for (j = 0 ; j < number ; ++j)
{
cout <<setw(5)<<total;
total -= 1;
}
cout <<endl;
}
cout <<endl;

//(2)
i = 0;
j = 0;
int num = 1;
vector< vector<int> > a;
a.resize(number);
for (int x = 0; x < number; ++x)
a[x].resize(number);
while(num <= number * number)
{
if(i == 0 || j == number)
{
if(j == number){
i+=1;
j--;
}
for(; j >= 0 && i != number; --j){
a[i][j] = num;
num++;
i++;
}
++j;
}
else if (j == 0 || i == number)
{
if (i == number){
j+=1;
i--;
}
for(; i >= 0 && j != number; --i){
a[i][j] = num;
num++;
j++;
}
++i;
}

}
for ( i = 0 ; i < number ; ++i)
{
for (int j = 0 ; j < number ; ++j)
cout <<setw(5)<<a[i][j];
cout <<endl;
}
cout <<endl;

#27
HCL2007-06-17 12:55

//(3)
i = 0;
j = 0;
num = 0;
vector< vector<int> > b;
b.resize(number);
for (int y = 0; y < number; ++y)
b[y].resize(number);
int temp1 = 0;
int temp2 = number - 1;
for (int t = 0; t <= number/2; t++, temp1++,temp2--,++i,++j)
{
for(i = temp1; i < temp2; i++)
b[i][j] = ++num;
for(j = temp1; j < temp2; j++)
b[i][j] = ++num;
for(i = temp2; i > temp1; i--)
b[i][j] = ++num;
for(j = temp2; j > temp1; j--)
b[i][j] = ++num;
if(temp1 == temp2)
b[temp1][temp2] = ++num;
}

for ( i = 0 ; i < number ; ++i)
{
for (int j = 0 ; j < number ; ++j)
cout <<setw(5)<<b[i][j];
cout <<endl;
}
cout <<endl;
return 0;
}

#28
HCL2007-06-17 13:01
16题应该可以用二分法吧!

#29
jiaju1112007-06-17 13:29
以下是引用aipb2007在2007-6-17 11:19:51的发言:
大家讨论下16题最少称几次啊?
------------------------------------------------------------------

16. 设有8枚硬币a,b,c,d,e,f,g,h,其中有一枚硬币是伪造的。
真伪硬币的区别仅是重量不同,可能重,可能轻。今要求以天平为工具,用最少的
比较次数挑出伪造硬币,并鉴定它是重还是轻。

------------------------------------------------------------------
我用4次似乎多了!

3次就够了吧

第一次 a,b,c 对 d,e,f 若平衡……(简单)

若不平衡(如果左边重)(如果右边重同样道理,因为题目是对称的)

第二次 b,c,d对e,f,g

若平衡 则a偏重,问题解决

若不平衡(如果仍然是左边重)则是b,或c偏重,再称一次就解决了
(如果是左边轻)则是d偏轻,问题解决

#30
aipb20072007-06-17 14:11
以下是引用jiaju111在2007-6-17 13:29:09的发言:

3次就够了吧

第一次 a,b,c 对 d,e,f 若平衡……(简单)

若不平衡(如果左边重)(如果右边重同样道理,因为题目是对称的)

第二次 b,c,d对e,f,g

若平衡 则a偏重,问题解决

若不平衡(如果仍然是左边重)则是b,或c偏重,再称一次就解决了
(如果是左边轻)则是d偏轻,问题解决

帅就一个字!!!
呵呵

#31
HCL2007-06-17 14:48
厉害啊~佩服!
#32
野比2007-06-17 16:17
以下是引用jiaju111在2007-6-17 13:29:09的发言:

3次就够了吧

第一次 a,b,c 对 d,e,f 若平衡……(简单)

若不平衡(如果左边重)(如果右边重同样道理,因为题目是对称的)

第二次 b,c,d对e,f,g

若平衡 则a偏重,问题解决

若不平衡(如果仍然是左边重)则是b,或c偏重,再称一次就解决了
(如果是左边轻)则是d偏轻,问题解决

好像有些不对劲..
这里"若不平衡(如果仍然是左边重)则是b,或c偏重 / (如果是左边轻)则是d偏轻", 没有考虑到"e或f偏轻"的情况...
因为不能保证一定会把偏轻的那一个当成d拿到左边去(三选一)...所以分析时思路就被误导在"问题一定出在左边"上了.
之后再称已经没有意义了.

我个人认为, 3次只能找出假币, 要判断轻重必须称第4次.
假币判断方法:
1.左右各放2个, 平衡:剩下4个有假币; 不平衡:这4个有假币
2.在有假币的4个中, 取2个放上天平称, 平衡: 假币在剩下2个中; 不平衡:假币在这2个中
此时: 可以确定出A组:2个, 有假币; B组: 6个, 全部标准.
3.从A组取1个(标记A1), 和B组取1个标准硬币放到天平上比较.
平衡: 则A2为假币; 不平衡: A1为假币.

4.将假币与标准硬币做最后比较, 确定轻重.

#33
jiaju1112007-06-17 17:10
以下是引用野比在2007-6-17 16:17:55的发言:

好像有些不对劲..
这里"若不平衡(如果仍然是左边重)则是b,或c偏重 / (如果是左边轻)则是d偏轻", 没有考虑到"e或f偏轻"的情况...
因为不能保证一定会把偏轻的那一个当成d拿到左边去(三选一)...所以分析时思路就被误导在"问题一定出在左边"上了.
之后再称已经没有意义了.

我个人认为, 3次只能找出假币, 要判断轻重必须称第4次.
假币判断方法:
1.左右各放2个, 平衡:剩下4个有假币; 不平衡:这4个有假币
2.在有假币的4个中, 取2个放上天平称, 平衡: 假币在剩下2个中; 不平衡:假币在这2个中
此时: 可以确定出A组:2个, 有假币; B组: 6个, 全部标准.
3.从A组取1个(标记A1), 和B组取1个标准硬币放到天平上比较.
平衡: 则A2为假币; 不平衡: A1为假币.

4.将假币与标准硬币做最后比较, 确定轻重.

多谢指正啊,呵呵,不好意思!

不过我觉得还是可以只用3次:

第一次 a,b,c 对 d,e,f 若平衡……(简单)

若不平衡(如果左边重)(如果右边重同样道理,因为题目是对称的)

第二次 c,d,e 对f,g,h

若平衡 则a或b偏重,再称一次解决

若不平衡(如果仍然是左边重)则是c偏重或者f偏轻,再称一次解决
(如果是左边轻)则是d或e偏轻,再称一次解决


#34
野比2007-06-17 17:49
恩. 受启发了. 我发现我的方法可以改进.. 也只需要3次了!

假币判断方法:
1.左右各放2个, 平衡:剩下4个有假币; 不平衡:这4个有假币
2.在有假币的4个中, 取较的2个放上天平称, 平衡: 假币在剩下2个中, 且较; 不平衡:假币在这2个中, 且较
此时: 可以确定出A组:2个, 有假币; B组: 6个, 全部标准.
3.从A组取1个(标记A1), 和B组取1个标准硬币放到天平上比较.
平衡: 则A2为假币; 不平衡: A1为假币.
假币轻重已由第2步得出
#35
jiaju1112007-06-17 18:00

楼上的方法似乎不对吧?

第1次如果平衡呢,第2次取哪两个比较?

#36
aipb20072007-06-17 18:09
都很不错,鉴定,可行!
赞哈!!!
#37
野比2007-06-17 18:19
发现问题了.. 我的方法最差情况(一直平衡)会出现第3步只能确定出假币(1/2).而无法得到假币轻重...
多谢jiaju111兄提醒..
#38
aipb20072007-06-17 20:12
to jiaju111:

很厉害也!怎么想到的???我想了N久也是4次!
你怎么捕捉这个思想的???分享一下哈!!!
#39
jiaju1112007-06-17 20:29

谢谢!

其实我也是碰运气刚好想到而已

感觉这个就跟心理上的“换位思考”差不多

具体我也说不清楚,呵呵,不好意思啊

#40
aipb20072007-06-17 20:32
以下是引用jiaju111在2007-6-17 20:29:12的发言:

谢谢!

其实我也是碰运气刚好想到而已

感觉这个就跟心理上的“换位思考”差不多

具体我也说不清楚,呵呵,不好意思啊


#41
野比2007-06-17 20:43
不管怎么说, 赞一个先
#42
HCL2007-06-17 21:07

都是牛人!
呵呵

#43
天下第二刀2007-06-17 23:32

顶 看看先

[此贴子已经被作者于2007-6-17 23:37:46编辑过]

#44
yuyunliuhen2007-06-18 11:56

NO.19:
Greedy Algorithms;

Analysis:
Remove item j from this load, the remaining load must be the

most valuable load weighing at most max - weight(j) that we can take from the n - 1 original items excluding j.
To solve the problem, we first compute the value per pound

value(i)/weight(i) for each item. Obeying a greedy strategy, we begins

by taking as much as possible of the item with the greatest value per

pound. If the supply of that item is exhausted and we can still carry

more, we takes as much as possible of the item with the next greatest

value per pound, and so forth until we can't carry any more. Thus, by

sorting the items by value per pound, the greedy algorithm runs in O(n

lg n) time.


#include<iostream>
using namespace std;
struct information
{
float price;
float weight;
float number;
int serial_number;
};
void sort_ascending(information good[],int n)// according to the ratio of price and weight,sort_ascending arrange
{
int i,j;
for(j=2;j<=n;j++)
{
good[0]=good[j];
i=j-1;
while(good[0].price>good[i].price)
{
good[i+1]=good[i];
i--;
}
good[i+1]=good[0];
}

}
void backpack(information good[],float max,int n)
{
float left;
int i,j;
for(i=1;i<n;i++)
good[i].number=0;
left=max;
for(i=1;i<n;i++)
{
if(good[i].weight>left)
break;
good[i].number=1;
left=left-good[i].weight;
}
if(i<=n)
good[i].number=left/good[i].weight;


for(j=2;j<n;j++) //according to good'serial number,from high to low
{
good[0]=good[j];
i=j-1;
while(good[0].serial_number<good[i].serial_number)
{
good[i+1]=good[i];
i--;
}
good[i+1]=good[0];
}
cout<<"The most excellent result is:"<<endl;
for(i=1;i<=n;i++)
{
cout<<"The "<<i<<"th good should input: ";
cout<<good[i].number<<endl;
}
}
int main()
{
int i,j;
int n;
float max;
information *good;
while(j)
{
cout<<"Please input goods's number: "<<endl;
cin>>n;
good=new struct information [n+1];
cout<<"Please input the max of goods's capability"<<endl;
cin>>max;
cout<<endl;
int i;
for(i=1;i<=n;i++)
{
good[i].serial_number=i;
cout<<"Please input the "<<i<<"th goods'weight:"<<endl;
cin>>good[i].weight;
cout<<"Please input the "<<i<<"th goods'price:"<<endl;
cin>>good[i].price;
good[i].price=good[i].price/good[i].weight;
cout<<endl;
}
sort_ascending(good,n);
backpack(good,max,n);

break;
}
system("pause");
return 0;
}


[此贴子已经被作者于2007-6-19 11:31:34编辑过]

#45
jiaju1112007-06-18 13:19
//第16题代码;
//完全是按顺序编写的,不带技术含量的,也不知道是否符合题意,呵呵

#include<iostream>
using namespace std;
int main()
{
int result;
cout << "第一次:称 abc和def"<<endl;
cout << "输入称量结果(平衡输入0;左重输入1;右重输入2):";
cin >> result;
if (result==0) //第一次称,平衡的情况
{
cout <<"第二次:称 a和g"<<endl;
cout << "输入称量结果(平衡输入0;左重输入1;右重输入2):";
cin >> result;
if (result==0)
{
cout <<"第三次:称 a和h"<<endl;
cout << "输入称量结果(左重输入1;右重输入2):"; //此时不可能平衡
cin >> result;
if (result==1)
{
cout <<"结果: h 偏轻"<<endl;
}
else
{
cout <<"结果: h 偏重"<<endl;
}
}
else if (result==1)
{
cout <<"结果: g 偏轻"<<endl;
}
else
{
cout <<"结果: g 偏重"<<endl;
}
}
else if (result==1) //第一次称,左重的情况
{
cout <<"第二次:称 cde和fgh"<<endl;
cout << "输入称量结果(平衡输入0;左重输入1;右重输入2):";
cin >> result;
if (result==0)
{
cout <<"第三次:称 a和b"<<endl;
cout << "输入称量结果(左重输入1;右重输入2):"; //此时不可能平衡
cin >> result;
if (result==1)
{
cout <<"结果: a 偏重"<<endl;
}
else
{
cout <<"结果: b 偏重"<<endl;
}
}
else if (result==1) //第二次称,左重的情况
{
cout <<"第三次:称 a和c"<<endl;
cout << "输入称量结果(平衡输入0;右重输入2):"; //此时不可能左重
cin >> result;
if (result==0)
{
cout <<"结果: f 偏轻"<<endl;
}
else
{
cout <<"结果: c 偏重"<<endl;
}
}
else //第二次称,右重的情况
{
cout <<"第三次:称 a和d"<<endl;
cout << "输入称量结果(平衡输入0;左重输入1):"; //此时不可能右重
cin >> result;
if (result==0)
{
cout <<"结果: e 偏轻"<<endl;
}
else
{
cout <<"结果: d 偏轻"<<endl;
}
}
}
else //第一次称,右重的情况
{
cout <<"第二次:称 cde和fgh"<<endl;
cout << "输入称量结果(平衡输入0;左重输入1;右重输入2):";
cin >> result;
if (result==0)
{
cout <<"第三次:称 a和b"<<endl;
cout << "输入称量结果(左重输入1;右重输入2):"; //此时不可能平衡
cin >> result;
if (result==1)
{
cout <<"结果: b 偏轻"<<endl;
}
else
{
cout <<"结果: a 偏轻"<<endl;
}
}
else if (result==2) //第二次称,右重的情况
{
cout <<"第三次:称 a和c"<<endl;
cout << "输入称量结果(平衡输入0;左重输入1):"; //此时不可能右重
cin >> result;
if (result==0)
{
cout <<"结果: f 偏重"<<endl;
}
else
{
cout <<"结果: c 偏轻"<<endl;
}
}
else //第二次称,左重的情况
{
cout <<"第三次:称 a和d"<<endl;
cout << "输入称量结果(平衡输入0;右重输入2):"; //此时不可能左重
cin >> result;
if (result==0)
{
cout <<"结果: e 偏重"<<endl;
}
else
{
cout <<"结果: d 偏重"<<endl;
}
}
}
return 0;
}
#46
aipb20072007-06-18 13:54

11. 巧排数字。将1、2、...、20这20个数排成一排,使得相邻的两个数之
和为一个素数,且首尾两数字之和也为一个素数。编程打印出所有的排法。
--------------------------------------------------------------------------------------
[CODE]/*
title : NO.11
author : aipb2007
date : 2007-06-18

analysis :
It's problem like "N queen",both use the algorithm of recursion and backtracking.
Use an array to store the solution.

design :
//print one solution
print(int a[],int n);
//check an integer is already in the array
bool is_in(int a[],int n,int in);
//check a number is a prime number
bool is_prime(double num);
//recursive function for backtracking
void solution(int a[],int n,int k);

in addition:
The questions has a problem, it's so many solution for 20 numbers.By using this
way,the computer will use a large time to do this,maybe can not.
However,maybe my program has a low efficiency.
So I change the number to 8,just for testing.

sample output :
1 2 3 8 5 6 7 4
1 2 5 8 3 4 7 6
1 4 7 6 5 8 3 2
1 6 7 4 3 8 5 2
2 1 4 7 6 5 8 3
2 1 6 7 4 3 8 5
2 3 8 5 6 7 4 1
2 5 8 3 4 7 6 1
3 2 1 4 7 6 5 8
3 4 7 6 1 2 5 8
3 8 5 2 1 6 7 4
3 8 5 6 7 4 1 2
4 1 2 3 8 5 6 7
4 3 8 5 2 1 6 7
4 7 6 1 2 5 8 3
4 7 6 5 8 3 2 1
5 2 1 6 7 4 3 8
5 6 7 4 1 2 3 8
5 8 3 2 1 4 7 6
5 8 3 4 7 6 1 2
6 1 2 5 8 3 4 7
6 5 8 3 2 1 4 7
6 7 4 1 2 3 8 5
6 7 4 3 8 5 2 1
7 4 1 2 3 8 5 6
7 4 3 8 5 2 1 6
7 6 1 2 5 8 3 4
7 6 5 8 3 2 1 4
8 3 2 1 4 7 6 5
8 3 4 7 6 1 2 5
8 5 2 1 6 7 4 3
8 5 6 7 4 1 2 3
*/


#include <iostream>
#include <cmath>
using namespace std;
void print(int a[],int n){
for (int i = 0; i < n;++i)
cout << a[i] << " ";
cout << endl;
}

bool is_in(int a[],int n,int in){
for (int i = 0;i < n;++i)
if (in == a[i])
return true;
return false;
}

bool is_prime(double num){
double d = sqrt(num);
for (int i = 2;i <= (int)d;++i)
if ((int)num % i == 0)
return false;
return true;
}

void solution(int a[],int n,int k){
if (k == n && is_prime(a[k-2]+a[k-1]) && is_prime(a[0]+a[k-1]))
print(a,n);
else if (k < 2 || is_prime(a[k-2]+a[k-1])){
for (int i = 1;i <= n;++i)
if (!is_in(a,k,i)){
a[k] = i;
solution(a,n,k+1);
}
}
}

int main(){
int a[8];
solution(a,8,0);
}[/CODE]


[此贴子已经被作者于2007-6-18 19:27:26编辑过]

#47
xiaohhyong2007-06-18 14:40
好多题看不懂拉,各位大大指点一下
#48
HJin2007-06-18 17:27

/*---------------------------------------------------------------------------
File name: C76-75.cpp
Author: HJin
Date: 6/18/2007

6/18/2007
-----------------------------------------------------------
1. Refine the analysis: provide optimal substructure and the
recurrence formula for c[p].

C76-75.cpp --- the cpp source file for solving the 75th of the 76
classical C/C++ problems.

经典 76 道编程题 之 75:

75. (钱币系统问题) 某钱币系统由 k (k≤20) 种硬币组成, 币值依次为 a[1],
a[2],...,a[k], 其中 a[i] (i=1,2,...,k) 为互不相同的正整数, 且依降序排列,
a[1]≤200. 给定某整数币值 n(n≤3000), 要求用最少枚数的硬币表示这个币值.
输入: 用文件输入已知数据, 格式为:
第 1 行: k (硬币种数)
第 2 行: a[1] a[2] ... a[k] (各币值用空格隔开,已按降序排列好)
第 3 行: n (给定的币值)
输出: 直接在屏幕上输出结果. 如果该钱币系统无法表示币值 n,应输出'No',
否则按以下格式输出:
第 1 行: 最少钱币枚数 r.
第 2 行: 输出若干形如 m*n 的表达式, m 为币值, n为使用该币值的枚数.
各式第 2 个因子之和应等于 r, 各式乘积之和应等于 n.
例: 设 (a[1],a[2],a[3])=(5,2,1), n=12, 则应输出
3
5*2 2*1.


Analysis:

1. If 1 is in the set { a[1], a[2], ..., a[k] }, then we can change
any number n in at most n cions (since n = 1*n);

2. There is some set { a[1], a[2], ..., a[k] } such that this coin
changing problem can be solved by a greedy algorithm. For exmaple,

{5, 2, 1}

is such a set. And there exists a set { a[1], a[2], ..., a[k] }
such that the greedy algorithm does not give an optimal soln. For
example,

{5, 4, 1}

is such a set: 8 = 5*1 + 1*3 is the greedy soln, which needs 4 cions,
whereas 8 = 4*2 tells us that we can use just 2 coins.


3. A dynamic programming algorithm exists for any set. This needs some
understanding of the topic. Cormen's book is a wonderful reference.

4. This is really a classical and an interesting problem and a lot of
references exist. Just google for "coin changing problem, dynamic programming".

5. This problem needs more analysis than programming efforts. A complete
soln of this problem needs to describe (and prove) the optimal substructure,
which we omitted.

6. Our soln does NOT fulfil the requirements described in the problem
statement.

7. The optimal substructure:

Write n = m + (n-m). Then the left half of an optimal soln for n must
be an optimal soln for m, the right half of the optimal soln for n must
be an optimal soln for n-m.

8. Let c[p] be the minimum number of coins to make change for n, then

c[p] = 0, if p = 0;
= 1 + min { 1 + c[ p-a[i] ]: a[i] <= p}, if p> 0


Sample output:


n=0, No
n=1, No
n=2, No
n=3, No
n=4, No
n=5, No
n=6, No
n=7, r=1: 7*1
n=8, No
n=9, No
n=10, No
n=11, No
n=12, No
n=13, No
n=14, r=2: 7*2
n=15, r=1: 15*1
n=16, No
n=17, No
n=18, No
n=19, No
n=20, No
n=21, r=3: 7*3
n=22, r=2: 15*1 7*1
n=23, No
n=24, No
n=25, No
n=26, No
n=27, No
n=28, r=4: 7*4
n=29, r=3: 15*1 7*2
n=30, r=2: 15*2
n=31, r=1: 31*1
n=32, No
n=33, No
n=34, No
n=35, r=5: 7*5
n=36, r=4: 15*1 7*3
n=37, r=3: 15*2 7*1
n=38, r=2: 31*1 7*1
n=39, No
n=40, No
n=41, No
n=42, r=6: 7*6
n=43, r=5: 15*1 7*4
n=44, r=4: 15*2 7*2
n=45, r=3: 15*3
n=46, r=2: 15*1 31*1
n=47, No
n=48, No
n=49, r=7: 7*7
n=50, r=6: 15*1 7*5
n=51, r=5: 15*2 7*3
n=52, r=4: 15*3 7*1
n=53, r=3: 15*1 31*1 7*1
n=54, No
n=55, No
n=56, r=8: 7*8
n=57, r=7: 15*1 7*6
n=58, r=6: 15*2 7*4
n=59, r=5: 15*3 7*2
n=60, r=4: 15*4
n=61, r=3: 15*2 31*1
n=62, r=2: 31*2
n=63, r=9: 7*9
n=64, r=8: 15*1 7*7
n=65, r=7: 15*2 7*5
n=66, r=6: 15*3 7*3
n=67, r=5: 15*4 7*1
n=68, r=4: 15*2 31*1 7*1
n=69, r=3: 31*2 7*1
n=70, r=10: 7*10
n=71, r=9: 15*1 7*8
n=72, r=8: 15*2 7*6
n=73, r=7: 15*3 7*4
n=74, r=6: 15*4 7*2
n=75, r=5: 15*5
n=76, r=4: 15*3 31*1
n=77, r=3: 15*1 31*2
n=78, r=10: 15*1 7*9
n=79, r=9: 15*2 7*7
n=80, r=8: 15*3 7*5
n=81, r=7: 15*4 7*3
n=82, r=6: 15*5 7*1
n=83, r=5: 15*3 31*1 7*1
n=84, r=4: 15*1 31*2 7*1
n=85, r=11: 15*1 7*10
n=86, r=10: 15*2 7*8
n=87, r=9: 15*3 7*6
n=88, r=8: 15*4 7*4
n=89, r=7: 15*5 7*2
n=90, r=6: 15*6
n=91, r=5: 15*4 31*1
n=92, r=4: 15*2 31*2
n=93, r=3: 31*3
n=94, r=10: 15*3 7*7
n=95, r=9: 15*4 7*5
n=96, r=8: 15*5 7*3
n=97, r=7: 15*6 7*1
n=98, r=6: 15*4 31*1 7*1
n=99, r=5: 15*2 31*2 7*1
Press any key to continue . . .

Reference:
1. Thomas H. Cormen, introduction to algorithms.

2. 野比, 相当经典的76道编程自虐题分享.无答案 at
https://bbs.bc-cn.net/viewthread.php?tid=147853
*/


#include <iostream>
#define INFPOS ~(1<<31) // (2^31-1)
#define DIM(x) (sizeof( (x) ) / sizeof( (x)[0] ))
using namespace std;

/**
@param a --- the array { a[1], a[2], ..., a[k] }. It does not
need to in decreasing order.
@param k --- number of coins
@param n --- the target number we want to make change
@return --- returns the minimum (positive) number of coins needed
to make a successful change; or -1 if the money system
cannot make the change.

Space complexity is Theta(n+k) --- there is a version of dynamic
programming algorithm which uses Theta(n*k) space. Obviously,
our version beats that version.
Time complexity is Theta(n * k).

Note that our algorithm does not require the set to be sorted beforehand.
*/
int change(int *a, int k, int n, bool print= true);

/**
print the optimal soln.
*/
int makeChange(int *a, int k, int n, int* b, bool print);


int main(int argc, char** argv)
{
//int a[] = {5, 4, 3};
int a[] = {15, 31, 7};
int k = DIM(a);
int n;
int res;

// test #1
for(n=0; n<100; ++n)
change(a, k, n);

// test #2
//for(n=40; n<80; ++n)
//{
// res = change(a, k, n, false);
// if(res == -1)
// cout<<n<<endl;
//}

return 0;
}

int change(int *a, int k, int n, bool print)
{
/**
c --- c[i] stores soln for n = i. If there is no soln for n=i,
then stores INFPOS;
s --- s[i] stores the index of the first coin for n=i. If there is
no soln for n =i, then stores INFPOS;
b --- b[j] stores the number of cions for the soln.
*/

int* c = new int[n+1];
int* s = new int[n+1];
int* b = new int[k];
int coinIndex=INFPOS;
int n2 = n;
int min;
int i;
int p;
int temp;

for(i=0; i<k; ++i)
b[i] = 0;

c[0] = 0; // n=0 needs zero coins to make
s[0] = INFPOS; // no coins can be used for n = zero

for(p=1; p<=n; ++p) // for face value 1 to n
{
min = INFPOS; // +\inf
for(i=0; i<k; ++i) // loop over the set of coins
{
if(a[i] <= p)
{
// temp implements the relation: 1 + +\inf = +\inf
temp = (c[p-a[i]] == INFPOS ? INFPOS : 1 + c[p-a[i]]);
if (min > temp )
{
min = temp; // keeps the local minimum
coinIndex = i; // select coin i
}
}
}

c[p] = min; // keeps the global min (the soln for n=p)
s[p] = coinIndex;
}

/**
build number of cions for each a[i] and store it in b[i]
*/
while(n2>0)
{
if( s[n2]>=0 && s[n2] <k )
++b[s[n2]];

n2 -= a[s[n2]];
}

// reuse n2 to keep a value
n2 = makeChange(a, k, n, b, print);

delete [] c;
delete [] s;
delete [] b;

return n2;
}


int makeChange(int *a, int k, int n, int* b, bool print)
{
int i;
int r=0;
int sum = 0;

if(print)
cout<<"n="<<n;

/**
calculate r --- the total number of cions for n
*/
for(i=0; i<k; ++i)
{
r+= b[i];
sum += b[i] * a[i];
}

/**
If the sum is not n, then there are no solns.
And treat the case n=0 as there are no solns.
*/
if (sum != n || n<1)
{
if(print)
cout<<", No"<<endl;
return -1;
}

if(print)
cout<<", r="<<r<<":\t";
for(i=0; i<k; ++i)
{
if( b[i] > 0 )
{
if(print)
cout<<a[i]<<"*"<<b[i]<<" ";
}
}

if(print)
cout<<endl;

return r;
}

[此贴子已经被作者于2007-6-19 3:01:51编辑过]

#49
HJin2007-06-18 17:29

/*---------------------------------------------------------------------------
File name: C76-49.cpp
Author: HJin
Date: 6/16/2007

C76-49.cpp --- the cpp source file for solving the 49th of the 76
classical C/C++ problems.

经典 76 道编程自虐题 之 49:

49. 有面值为 M..N 的邮票各一枚,共能拼出多少不同的面额。


Analysis:

Let

y = x_M a[M] + x_{M+1} a[M+1] + ... + x_{N} a[N],

where

a[j] = j,
x_j is either 0 or 1

for M <= j <= N. x_j = 0 means the jth item (a[j])
is not picked in the sum; x_j = 1 means the jth item
is picked in the sum. Thus, we have 2^{N-M+1} possible
sums, of which some may repeat.

Our task is to count how many sums are distinct among these
2^{N-M+1} possibilites.

The following algorithms all run in O(2^{N-M+1}) time. A better
approach would be to apply some dynamic programming techniques,
which could give us polynomial running time.


Sample output:

1 3
2 4
3 5
4 6
5 7
6 8
7 9
8 10
9 11
10 12
11 13
12 14
13 15
14 18
total number of face values are 14
Press any key to continue . . .


Reference:

野比, 相当经典的76道编程自虐题分享.无答案 at
https://bbs.bc-cn.net/viewthread.php?tid=147853


*/


#include <iostream>
#include <set>
using namespace std;


/**
This function computes the result for M=1 and N.
*/
void test1N(int N, int& sum)
{
static int count=0; // counter

if(N==0)
{
++count;
cout<<count<<"\t"<<sum<<endl;
return;
}
else
{
/**
a[N] is not picked.
*/
int temp = sum; // remember previous sum
test1N(N-1, sum);

/**
a[N] is picked.
*/
sum = temp; // restore previous sum
sum += N;
test1N(N-1, sum);
}
}

/**
This function computes the result for M and N.
*/
void testMN(int M, int N, int& sum)
{
static int count=0; // counter

if(N==M-1)
{
++count;
cout<<count<<"\t"<<sum<<endl;
return;
}
else
{
int temp = sum;
testMN(M, N-1, sum);

sum = temp;
sum += N;
testMN(M, N-1, sum);
}
}


/**
This function computes the result for M and N and
put the sums in a set.
*/
void testMN(int M, int N, int& sum, set<int>& s)
{
if(N==M-1)
{
s.insert(sum);
return;
}
else
{
int temp = sum;
testMN(M, N-1, sum, s);

sum = temp;
sum += N;
testMN(M, N-1, sum, s);
}
}

/**
This function wraps the testMN function and returns
the total number of different sums.
*/
int testMN_Total(int M, int N, bool print=true)
{
set<int> s;
int sum=0;
testMN(M, N, sum, s);
int counter = -1;

if(print)
{
for(set<int>::const_iterator iter = s.begin(); iter != s.end(); ++iter)
{
++counter;

/** get rid of the case in which all x[j] = 0; i.e.,
the case none of the stamps is picked.
*/
if(counter)
cout<<counter<<"\t"<<*iter<<endl;
}
}

return s.size()-1;
}


int main(int argc, char** argv)
{
//cout<<"total number of face values are "<<testMN_Total(3, 7)<<endl;
for(int i=0; i<10; ++i)
{
cout<<
testMN_Total(1, 1+i, false)<<"\t"<<
testMN_Total(2, 2+i, false)<<"\t"<<
testMN_Total(3, 3+i, false)<<"\t"<<
testMN_Total(4, 4+i, false)<<"\t"<<
testMN_Total(5, 5+i, false)<<"\t"<<
testMN_Total(6, 6+i, false)<<"\t"<<
testMN_Total(7, 7+i, false)<<"\t"<<
testMN_Total(8, 8+i, false)<<"\t"<<
testMN_Total(9, 9+i, false)<<"\t"<<
//testMN_Total(10, 10+i, false)<<"\t"<<
endl;
}

return 0;
}

#50
野比2007-06-18 19:35
HJin老兄, 你太XX了吧... 连下两程... 实在佩服..
不过49题main函数带上参数干嘛? 好像用不到命令行哦..
#51
野比2007-06-18 20:06
回复:(jiaju111)//第16题代码;//完全是按顺序编写...
jiaju111兄... 很明显题目是要遍历各种情况...不是自己输入..
123456