Upload
kylemore-losty
View
36
Download
1
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
程序设计实习习题课
http://ai.pku.edu.cn/cpp2010
习题课
2951 浮点数高精度求幂2775 文件结构图2787 算 24acm3278 catch the cowAcm1321 棋盘问题
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 。如果输出是整数,不要输出小数点。
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
2951
思路:以 95.123 12 为例1. 求出小数部分长度 – 3 位2. 去掉小数点,变成整数 95.123 -> 951233. 求 95123^12 =
548815620517731830194541899025343415715973535967221869852721
4. 重新点小数点548815620517731830194541.899025343415715973535967221869852721
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;
}}
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;
}
2775 文件结构图file1file2dir3dir2file1file2]]file4dir1]file3*file2file1*#
DATA SET 1:ROOT| dir3| | dir2| | file1| | file2| dir1file1file2file3file4
DATA SET 2:ROOTfile1file2
2775 文件结构图file1file2dir3dir2file1file2]]file4dir1]file3*file2file1*#
回想表达式处理的题目 , 没有必要在内存生成整个目录树 , 因为整个目录树已经以递归的结构存储在输入数据里了 .
因此递归处理输入数据的过程就是递归遍历整个目录树的过程。
递归过程中,碰到目录名就立刻输出,按题目要求,碰到文件名不能立刻输出,要存起来,等整个目录处理完后,再排序输出。
#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);}
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;
}
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;
case 'f':strcpy( vFiles[nTotalFiles ++],sLine);break;
case 'd':nCurLevel ++;// 要进入一个文件夹,层次增加ListDir( sLine);break;
}}while(1);
}
2787 算 24
输入:5 5 5 1
1 1 4 2
0 0 0 0
输出:YES
NO
2787 算 24
子问题: k 个数算 24
递归:从 k 个数算 24 ,规约到 k-1 个数算 24
方法:从 k 个数中选 2 个数 a 和 b ,及一种运算op ;将 a 和 b 从 k 个数中删除,再将 (a op b)加入
#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;
}
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;
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; // 各种方法都算不出来,则断定不成功
}
acm1321 棋盘问题在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放 k个棋子的所有可行的摆放方案 C。Input
输入含有多组测试数据。每组数据的第一行是两个正整数, n k,用一个空格隔开,表示了将在一个 n*n 的矩阵内描述棋盘,以及摆放棋子的数目。 n <= 8 , k <= n 当为 -1 -1 时表示输入结束。随后的 n行描述了棋盘的形状:每行有 n 个字符,其中 # 表示棋盘区
域, . 表示空白区域(数据保证不出现多余的空白行或者空白列)。
Output对于每一组数据,给出一行输出,输出摆放的方案数目 C (数据保证C<2^31)。
acm1321 棋盘问题
Sample Input2 1 #. .# 4 4 ...# ..#. .#..#...-1 -1 Sample Output2 1
acm1321 棋盘问题
思路:
和八皇后几乎一样,不同之处在于可以有不摆棋子的空行
所以要两个变量记录一下已经摆了多少空行 , 和多少个棋子已经摆好
#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;
}
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 --;
}}
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 --;
}}
}
}
}
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?
acm3278 Catch That Cow
广度优先搜索如果忘了判重,就会 RLE如果不剪枝,就会 RLE剪枝:
1) 没必要走到 x<0 的位置2) 如果已经在牛的右边,就不该再往右走3) 如果往右跳后,和牛的距离变得更远了,那就不要往右
边跳
如果没有注意到人可能需要走到牛的右边,判重的标志数组不够大,就会 RLE
#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;
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 ++;
}}
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 ++;
}}