29
程程程程程程 习习习 http://ai.pku.edu.cn/cpp2010

程序设计实习

Embed Size (px)

DESCRIPTION

程序设计实习. 习题课 http://ai.pku.edu.cn/cpp2010. 习题课. 2951 浮点数高精度求幂 2775 文件结构图 2787 算 24 acm3278 catch the cow Acm1321 棋盘问题. 2951. 题目描述:有一个实数 R ( 0.0 < R < 99.999 ) , 要求写程序精确计算 R 的 n 次方。 n 是整数并且 0 < n

Citation preview

Page 1: 程序设计实习

程序设计实习习题课

http://ai.pku.edu.cn/cpp2010

Page 2: 程序设计实习

习题课

2951 浮点数高精度求幂2775 文件结构图2787 算 24acm3278 catch the cowAcm1321 棋盘问题

Page 3: 程序设计实习

2951

题目描述:有一个实数 R ( 0.0 < R < 99.999 ) , 要求写程序精确计算 R 的 n 次方。 n 是整数并且 0 < n <= 25 。输入:输入包括多组 R 和 n 。 R 的值占第 1 到 第 6 列 , n 的值占第 8 和第 9 列。输出:对于每组输入,要求输出一行,该行包含精确的 R 的 n 次方。输出需要去掉前导的 0 后后面不不要的 0 。如果输出是整数,不要输出小数点。

Page 4: 程序设计实习

2951

95.123 12

0.4321 20

5.1234 15

6.7592 9

98.999 10

1.0100 12

548815620517731830194541.899025343415715973535967221869852721

.00000005148554641076956121994511276767154838481760200726351203835429763013462401

43992025569.928573701266488041146654993318703707511666295476720493953024

29448126.764121021618164430206909037173276672

90429072743629540498.107596019456651774561044010001

1.126825030131969720661201

Page 5: 程序设计实习

2951

思路:以 95.123 12 为例1. 求出小数部分长度 – 3 位2. 去掉小数点,变成整数 95.123 -> 951233. 求 95123^12 =

548815620517731830194541899025343415715973535967221869852721

4. 重新点小数点548815620517731830194541.899025343415715973535967221869852721

Page 6: 程序设计实习

2951 代码#include<stdio.h>#include<string.h>const int MAX=100;char s[7];int a[MAX],e,p,b,be,en,i;void mul(){

int i,w=0;for(i=0;i<MAX;i++){

a[i]=a[i]*b+w;w=a[i]/10;a[i]=a[i]-w*10;

}}

Page 7: 程序设计实习

int main(){

while (scanf("%s %d",s,&e)!=EOF){

memset(a,0,sizeof(a));b=0; //Step 1 and Step 2for(i=0;i<strlen(s);i++)

if (s[i]=='.') p=strlen(s)-i-1;else b=b*10+s[i]-'0';

a[0]=1; //Step 3for(i=0;i<e;i++)

mul();p*=e; //Step 4for (be=MAX-1;a[be]==0&&be>=p-1;be--);for (en=0;a[en]==0&&en<p;en++);for (i=be;i>=p;i--) printf("%d",a[i]);if (en<p) printf(".");for (i=p-1;i>=en;i--) printf("%d",a[i]);printf("\n");

}return 0;

}

Page 8: 程序设计实习

2775 文件结构图file1file2dir3dir2file1file2]]file4dir1]file3*file2file1*#

DATA SET 1:ROOT| dir3| | dir2| | file1| | file2| dir1file1file2file3file4

DATA SET 2:ROOTfile1file2

Page 9: 程序设计实习

2775 文件结构图file1file2dir3dir2file1file2]]file4dir1]file3*file2file1*#

回想表达式处理的题目 , 没有必要在内存生成整个目录树 , 因为整个目录树已经以递归的结构存储在输入数据里了 .

因此递归处理输入数据的过程就是递归遍历整个目录树的过程。

递归过程中,碰到目录名就立刻输出,按题目要求,碰到文件名不能立刻输出,要存起来,等整个目录处理完后,再排序输出。

Page 10: 程序设计实习

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

void ListDir( const char * root); // 处理文件夹int nCurLevel = 0; // 记录当前所在的目录层次int MyCompare( const void * e1, const void * e2)// 对文件名排序的比较函数{

return strcmp( (const char * ) e1, (const char * ) e2);}

Page 11: 程序设计实习

int main() {int nDatasetNo = 1;do {

cout << "DATA SET "<< nDatasetNo << ":" << endl;

nCurLevel = 0;ListDir("ROOT"); // 处理根目录// 下面处理下一个 test casechar c;do { // 跳过回车换行符

c = cin.peek();if( c == '\r' || c == '\n' )

cin.get();}while( c == '\r' || c == '\n');if( c == '#')

break;else {

cout << endl;nDatasetNo ++;

}}while(1);return 0;

}

Page 12: 程序设计实习

void ListDir( const char * root){

char sLine[200];char vFiles[200][30] ; int nTotalFiles = 0;

int i,j;for( i = 0;i < nCurLevel; i ++ )

cout << "| ";cout << root << endl;do {

cin >> sLine;switch( sLine[0] ) {

case '*':case ']':

qsort( vFiles, nTotalFiles,30,MyCompare);for( j = 0 ; j < nTotalFiles; j ++ ) {

for( i = 0;i < nCurLevel; i ++ )cout << "| ";

cout <<vFiles[j] << endl;}nCurLevel --;// 处理完一个文件夹,退到上一层return;

Page 13: 程序设计实习

case 'f':strcpy( vFiles[nTotalFiles ++],sLine);break;

case 'd':nCurLevel ++;// 要进入一个文件夹,层次增加ListDir( sLine);break;

}}while(1);

}

Page 14: 程序设计实习

2787 算 24

输入:5 5 5 1

1 1 4 2

0 0 0 0

输出:YES

NO

Page 15: 程序设计实习

2787 算 24

子问题: k 个数算 24

递归:从 k 个数算 24 ,规约到 k-1 个数算 24

方法:从 k 个数中选 2 个数 a 和 b ,及一种运算op ;将 a 和 b 从 k 个数中删除,再将 (a op b)加入

Page 16: 程序设计实习

#include <iostream>using namespace std;double Numbers[5];bool Calc( double * pNumbers, int n );// 用 pNumbers 数组里的 n 个数算 24 看能否成功int main() {

int a[4];int nZeroNum = 0;while(true) {

for( int i = 0;i < 4;i ++ ) {cin >> Numbers[i];if( Numbers[i] == 0 )

nZeroNum ++;}if( nZeroNum == 4 )

break;if( Calc( Numbers,4))

cout << "YES" <<endl;else

cout << "NO" << endl;}return 0;

}

Page 17: 程序设计实习

bool Calc( double * pNumbers, int n ){

int i,j,k;double aNumber[4];if( n == 1 ) { // 只有一个数要用来算 24 ,而且这个数就是 24 ,那么就成功

if( pNumbers[0] > 23.99999 && pNumbers[0] < 24.00001 )

return true;else

return false;}for( i = 0;i < n - 1;i ++ ) {

for( j = i + 1; j < n; j ++ ) { // 枚举两个数先算int m = 0;for( k = 0; k < n; k ++ ) {// 把剩下的数留住

if( k != i && k != j )aNumber[m++] = pNumbers[k];

}

// 用枚举出的两个数的和,以及剩下的数,继续算 24aNumber[m] = pNumbers[i] + pNumbers[j];if( Calc( aNumber, n -1 ))

return true;

Page 18: 程序设计实习

aNumber[m] = pNumbers[i] * pNumbers[j];if( Calc( aNumber, n -1 ))

return true;aNumber[m] = pNumbers[i] - pNumbers[j];if( Calc( aNumber, n -1 ))

return true;aNumber[m] = pNumbers[j] - pNumbers[i];if( Calc( aNumber, n -1 ))

return true;if( pNumbers[i] != 0) {

aNumber[m] = pNumbers[j] / pNumbers[i];if( Calc( aNumber, n -1 ))

return true;}if( pNumbers[j] != 0) {

aNumber[m] = pNumbers[i] / pNumbers[j];if( Calc( aNumber, n -1 ))

return true;}

}}return false; // 各种方法都算不出来,则断定不成功

}

Page 19: 程序设计实习

acm1321 棋盘问题在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k个棋子的所有可行的摆放方案 C。Input

输入含有多组测试数据。每组数据的第一行是两个正整数, n k,用一个空格隔开,表示了将在一个 n*n 的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n 当为 -1 -1 时表示输入结束。随后的 n行描述了棋盘的形状:每行有 n 个字符,其中 # 表示棋盘区

域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。

Output对于每一组数据,给出一行输出,输出摆放的方案数目 C (数据保证C<2^31)。

Page 20: 程序设计实习

acm1321 棋盘问题

Sample Input2 1 #. .# 4 4 ...# ..#. .#..#...-1 -1 Sample Output2 1

Page 21: 程序设计实习

acm1321 棋盘问题

思路:

和八皇后几乎一样,不同之处在于可以有不摆棋子的空行

所以要两个变量记录一下已经摆了多少空行 , 和多少个棋子已经摆好

Page 22: 程序设计实习

#include <iostream>using namespace std;char Grid[9][9]; int n,k; int nTotal = 0; // 总方案数int anPos[9];int nBlankRows = 0; int nDoneNum = 0; // 已摆好的棋子数目void Queen(int nRow);int main() {

int i,j;while( true) {

cin >> n >> k;if( n == -1 && k == -1 )

break;for( i = 0;i < n;i ++ )

for( j = 0;j < n; j ++ )cin >> Grid[i][j];

nTotal = 0; nBlankRows = 0; nDoneNum = 0;Queen(0); // 从第 0 行开始摆cout << nTotal << endl;

}return 0;

}

Page 23: 程序设计实习

void Queen(int nRow){

if( nRow == n || nDoneNum == k) {// 如果已经摆到第 n 行(行号从 0 开始),或者已经没有棋子要摆

了,// 则说明成功,总方案数要加 1

nTotal ++;return ;

}int i,j;for( i = -1; i < n; i ++ ) { // 逐个尝试摆放位置,摆在位置 -1 就代表该行是空行

if( i == -1 ) {if( nBlankRows < n - k ) {// 如果还能放空行

anPos[nRow] = -1;// 放空行nBlankRows ++;Queen( nRow + 1 ) ;

// 尝试本行新位置前,已摆放的空行数要复原nBlankRows --;

}}

Page 24: 程序设计实习

else {if( Grid[nRow][i] == '#' ) {

for( j = 0; j < nRow; j ++ )if( anPos[j] == i ) // 和前面的同列

break;if( j == nRow ) {

anPos[nRow] = i; // 第 nRow 行摆位置i

nDoneNum ++; // 已摆好棋子数加 1Queen(nRow + 1 );// 摆下一行// 尝试本行新位置前,已摆好棋子数// 要复原nDoneNum --;

}}

}

}

}

Page 25: 程序设计实习

acm3278 Catch That Cow

Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.

* Walking: FJ can move from any point X to the points X - 1 or X + 1 in a single minute* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.

If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?

Page 26: 程序设计实习

acm3278 Catch That Cow

广度优先搜索如果忘了判重,就会 RLE如果不剪枝,就会 RLE剪枝:

1) 没必要走到 x<0 的位置2) 如果已经在牛的右边,就不该再往右走3) 如果往右跳后,和牛的距离变得更远了,那就不要往右

边跳

如果没有注意到人可能需要走到牛的右边,判重的标志数组不够大,就会 RLE

Page 27: 程序设计实习

#include <iostream>#include <string>#include <memory>using namespace std;int n,k;struct SNode {

int x;int nSteps;

};SNode aQueue[3000000];int anRepeated[300000];int nHead,nTail;int main(){

cin >> n >> k;memset( anRepeated,0,sizeof(anRepeated));nHead = 0;nTail = 1;aQueue[0].x = n;aQueue[0].nSteps = 0;

Page 28: 程序设计实习

while( nHead != nTail ) {if( aQueue[nHead].x == k ) {

cout << aQueue[nHead].nSteps;return 0;

}if ( aQueue[nTail].x < k ) {

// 如果已经在牛右边,再往右边走一格是没有意义的aQueue[nTail].x = aQueue[nHead].x + 1;if( anRepeated[aQueue[nTail].x] == 0 ) {

aQueue[nTail].nSteps = aQueue[nHead].nSteps + 1;

anRepeated[aQueue[nTail].x] = 1;nTail++;

}}if( aQueue[nHead].x - 1 >= 0 ) {

aQueue[nTail].x = aQueue[nHead].x - 1;if( anRepeated[aQueue[nTail].x] == 0 ) {

aQueue[nTail].nSteps = aQueue[nHead].nSteps + 1;

anRepeated[aQueue[nTail].x] = 1;nTail++;

}}if( aQueue[nHead].x * 2 - k <= k - aQueue[nHead].x ) {

// 往右跳得太远没有意义aQueue[nTail].x = aQueue[nHead].x * 2;if( anRepeated[aQueue[nTail].x] == 0 ) {

aQueue[nTail].nSteps = aQueue[nHead].nSteps + 1;

anRepeated[aQueue[nTail].x] = 1;nTail++;

}}nHead ++;

}}

Page 29: 程序设计实习

if( aQueue[nHead].x * 2 - k <= k - aQueue[nHead].x ) {// 往右跳得太远没有意义aQueue[nTail].x = aQueue[nHead].x * 2;if( anRepeated[aQueue[nTail].x] == 0 ) {

aQueue[nTail].nSteps = aQueue[nHead].nSteps + 1;anRepeated[aQueue[nTail].x] = 1;nTail++;

}}nHead ++;

}}