290 likes | 457 Views
程序设计实习. 习题课 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 <= 25 。 输入:输入包括多组 R 和 n 。 R 的值占第 1 到 第 6 列 , n 的值占第 8 和第 9 列。
E N D
程序设计实习 习题课 http://ai.pku.edu.cn/cpp2010
习题课 2951 浮点数高精度求幂 2775 文件结构图 2787 算24acm3278 catch the cow Acm1321棋盘问题
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为例 • 求出小数部分长度 – 3位 • 去掉小数点,变成整数95.123 -> 95123 • 求95123^12 = 548815620517731830194541899025343415715973535967221869852721 • 重新点小数点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 2 for(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 3 for(i=0;i<e;i++) mul(); p*=e; //Step 4 for (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 文件结构图 DATA SET 1: ROOT | dir3 | | dir2 | | file1 | | file2 | dir1 file1 file2 file3 file4 DATA SET 2: ROOT file1 file2 file1 file2 dir3 dir2 file1 file2 ] ] file4 dir1 ] file3 * file2 file1 * #
2775 文件结构图 回想表达式处理的题目, 没有必要在内存生成整个目录树,因为整个目录树已经以递归的结构存储在输入数据里了. 因此递归处理输入数据的过程就是递归遍历整个目录树的过程。 递归过程中,碰到目录名就立刻输出,按题目要求,碰到文件名不能立刻输出,要存起来,等整个目录处理完后,再排序输出。 file1 file2 dir3 dir2 file1 file2 ] ] file4 dir1 ] file3 * file2 file1 * #
#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 case char 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]; } //用枚举出的两个数的和,以及剩下的数,继续算24 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[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 Input 2 1 #. .# 4 4 ...# ..#. .#.. #... -1 -1 Sample Output 2 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 ++; //已摆好棋子数加1 Queen(nRow + 1 );//摆下一行 //尝试本行新位置前,已摆好棋子数 //要复原 nDoneNum --; } } } } }
acm3278Catch 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?
acm3278Catch 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 ++; } }