<P><br>C76-48.cpp --- the cpp source file for solving the 48th of the 76<br>classical C/C++ problems.</P>
<P>经典 76 道编程题 之 48:</P>
<P>48. 将4个红球,3个白球与3个黄球排成一排,共有多少种排法?</P>
<P>Answer: binomial(10, 4) * binomial(6, 3) * binomial(3, 3) = 4200.</P>
<P>Analysis:</P>
<P>Allocate r+w+y (=10) slots. The job can be done in three steps:<br>(1) we put all r red balls into the r+w+y slots --- total is binomial(r+w+y, r)<br>(2) we put all w white balls into the remaining w+y slots --- total is binomial(w+y, y)<br>(3) we put all y yellow balls into the remaining y slots --- total is binomial(y, y) = 1</P>
<P>All in all, total is binomial(r+w+y, r) * binomial(w+y, y) * 1.</P>
<P>Programming thoughts:</P>
<P>Generate all 3^(r+w+y) possible choices (since each slot can have one of the <br>three colors ) and check if a choice is valid. A choice is valid if and only<br>if there are r red balls, w white balls, and y yellow balls.</P>
<P>We used a set in the implementation, since set does not store duplicates.</P>
<P>Sample output:</P>
<P>1 rrwy<br>2 rryw<br>3 rwry<br>4 rwyr<br>5 ryrw<br>6 rywr<br>7 wrry<br>8 wryr<br>9 wyrr<br>10 yrrw<br>11 yrwr<br>12 ywrr<br>total number of different combinations are 12<br>Press any key to continue . . .</P>
<P><br>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <br><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A><br>*/</P>
<P>#include <iostream><br>#include <set><br>#include <string><br>using namespace std;</P>
<P>string buffer;</P>
<P>/**<br>Time complexity is O(3^(r+w+y)) --- very inefficient.</P>
<P>build the set of all combinations.<br>*/<br>void buildSet(int r, int w, int y, int n, set<string>& s);</P>
<P>/**<br>wrap the function buildSet() and outputs results.<br>*/<br>int combination(int r, int w, int y, bool print = true);<br>/**<br>check if the string is valid.</P>
<P>A choice is valid if and only if there are r red balls, w white balls, and<br>y yellow balls.<br>*/<br>bool isValid(int r, int w, int y, string& str);</P>
<P><br>int main(int argc, char** argv)<br>{<br> // test #3<br> //int r=4;<br> //int w=3;<br> //int y=3;<br> <br> // test #2<br> //int r=3;<br> //int w=2;<br> //int y=2;<br> <br> // test #1<br> int r=2;<br> int w=1;<br> int y=1;</P>
<P> cout<<"total number of different combinations are "<<combination(r, w, y, true)<<endl;</P>
<P> return 0;<br>}</P>
<P>void buildSet(int r, int w, int y, int n, set<string>& s)<br>{<br> if(n==0)<br> {<br> if(isValid(r, w, y, buffer))<br> {<br> s.insert(buffer);<br> }</P>
<P> return;<br> }</P>
<P> string temp = buffer; // keep previous state</P>
<P> buffer+="r";<br> buildSet(r, w, y, n-1, s);</P>
<P> buffer = temp; // recall previous state<br> buffer+="w";<br> buildSet(r, w, y, n-1, s);</P>
<P> buffer = temp; // recall previous state<br> buffer+="y";<br> buildSet(r, w, y, n-1, s);<br>}</P>
<P>int combination(int r, int w, int y, bool print)<br>{<br> set<string> s;<br> int n = r+w+y;<br> int counter = 0;<br> <br> buildSet(r, w, y, n, s);</P>
<P> if(print) // print combinations<br> {<br> for(set<string>::const_iterator iter = s.begin(); iter!=s.end(); ++iter)<br> {<br> ++counter;<br> cout<<counter<<"\t"<<*iter<<endl;<br> }<br> }</P>
<P> return s.size();<br>}</P>
<P>bool isValid(int r, int w, int y, string& str)<br>{<br> int r_=0; // store # of red balls<br> int w_=0;<br> int y_=0;<br> bool res = false;</P>
<P> for(size_t i =0; i<str.size(); ++i)<br> {<br> switch(str[i])<br> {<br> case 'r':<br> ++r_;<br> break;<br> case 'w':<br> ++w_;<br> break;<br> case 'y':<br> ++y_;<br> break;<br> }<br> }</P>
<P> res = (r_==r) && (w_==w) && (y_==y);<br> <br> return res;<br>}<br></P>
[align=right][color=#000066][此贴子已经被作者于2007-6-19 6:17:01编辑过][/color][/align]
<P><BR>C76-10.cpp --- the cpp source file for solving the 10th of the 76<BR>classical C/C++ problems.</P>
<P>经典 76 道编程题 之 10:</P>
<P> 10. 如图1所示,编写程序计算 ┎┰┰┰┰┰┰┰┰┰┒<BR> 大大小小正方形共有多少?当最小 ┠╂╂╂╂╂╂╂╂╂┨<BR> 正方行边长为1时,它们的总面积 ┠╂╂╂╂╂╂╂╂╂┨<BR> 共为多少? ┠╂╂╂╂╂╂╂╂╂┨<BR> ┠╂╂╂╂╂╂╂╂╂┨<BR> ┠╂╂╂╂╂╂╂╂╂┨<BR> ┠╂╂╂╂╂╂╂╂╂┨<BR> ┠╂╂╂╂╂╂╂╂╂┨<BR> ┠╂╂╂╂╂╂╂╂╂┨<BR> ┠╂╂╂╂╂╂╂╂╂┨<BR> ┖┸┸┸┸┸┸┸┸┸┚</P>
<P>Analysis:</P>
<P>i | # of squares with side length i | total area<BR>----+------------------------------------------------<BR>n | 1^2 | n*1^2<BR>n-1 | 2^2 | (n-1)*2^2<BR>n-2 | 3^2 | (n-2)*3^2<BR>.....................................................<BR>2 | (n-2)^2 | 2*(n-2)^2<BR>1 | n^2 | 1*n^2</P>
<P>total number of squares is 1^2 + 2^2 +... +n^2 = n*(n+1)*(2*n+1)/6<BR>total area is 1*n^2 + 2*(n-1)^2 + ... + n*1^2 = n*(n+1)^2*(n+2)/12</P>
<P><BR>Sample output:</P>
<P>n | # of squares | total area | # of squares 2 | total area 2<BR>-----+--------------+--------------+----------------+---------------<BR>1 | 1 | 1 | 1 | 1<BR>2 | 5 | 6 | 5 | 6<BR>3 | 14 | 20 | 14 | 20<BR>4 | 30 | 50 | 30 | 50<BR>5 | 55 | 105 | 55 | 105<BR>6 | 91 | 196 | 91 | 196<BR>7 | 140 | 336 | 140 | 336<BR>8 | 204 | 540 | 204 | 540<BR>9 | 285 | 825 | 285 | 825<BR>10 | 385 | 1210 | 385 | 1210<BR>11 | 506 | 1716 | 506 | 1716<BR>12 | 650 | 2366 | 650 | 2366<BR>13 | 819 | 3185 | 819 | 3185<BR>14 | 1015 | 4200 | 1015 | 4200<BR>15 | 1240 | 5440 | 1240 | 5440<BR>16 | 1496 | 6936 | 1496 | 6936<BR>17 | 1785 | 8721 | 1785 | 8721<BR>18 | 2109 | 10830 | 2109 | 10830<BR>19 | 2470 | 13300 | 2470 | 13300<BR>-----+--------------+--------------+----------------+---------------<BR>Press any key to continue . . .</P>
<P>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <BR><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A><BR>*/</P>
<P>#include <iostream><BR>#include <iomanip><BR>using namespace std;</P>
<P>int numOfSquares(int n);<BR>int totalArea(int n);</P>
<P>int numOfSquares2(int n);<BR>int totalArea2(int n);</P>
<P>int main(int argc, char** argv)<BR>{<BR> cout<<"n | # of squares | total area | # of squares 2 | total area 2\n";<BR> cout<<"-----+--------------+--------------+----------------+---------------\n";<BR> <BR> for(int i=1; i<20; ++i)<BR> cout<<std::left<<setw(4)<<i<<" | "<BR> <<setw(12)<<numOfSquares(i)<<" | "<BR> <<setw(12)<<totalArea(i)<<" | "<BR> <<setw(14)<<numOfSquares2(i)<<" | "<BR> <<setw(12)<<totalArea2(i)<BR> <<endl;<BR> cout<<"-----+--------------+--------------+----------------+---------------\n";</P>
<P> return 0;<BR>}</P>
<P>int numOfSquares(int n)<BR>{<BR> int sum =0;<BR> for(int i=1; i<=n; ++i)<BR> sum += i*i;</P>
<P> return sum;<BR> return n*(n+1)*(2*n+1)/6;<BR>}</P>
<P>int numOfSquares2(int n)<BR>{<BR> // don't write n/6*(n+1)*(2*n+1)<BR> // this could give you 0, since 1/6 = 0<BR> return n*(n+1)*(2*n+1)/6;<BR>}</P>
<P>int totalArea(int n)<BR>{<BR> int area = 0;<BR> <BR> for(int i=1; i<=n; ++i)<BR> {<BR> area += i*(n+1-i)*(n+1-i);<BR> }</P>
<P> return area;<BR>}</P>
<P>int totalArea2(int n)<BR>{<BR> return n*(n+1)*(n+1)*(n+2)/12;<BR>}<BR></P> <P>/*---------------------------------------------------------------------------<BR>File name: C76-13.cpp<BR>Author: HJin<BR>Created on: 6/18/2007 15:15:52</P>
<P><BR>C76-13.cpp --- the cpp source file for solving the 13th of the 76<BR>classical C/C++ problems.</P>
<P>经典 76 道编程题 之 13:</P>
<P>13. 有N个硬币(N为偶数)正面朝上排成一排,每次将 N-1 个硬币翻过来放在原位<BR> 置, 不断地重复上述过程,直到最后全部硬币翻成反面朝上为止。编程让计算机把<BR> 翻币的最简过程及翻币次数打印出来(用*代表正面,O 代表反面)。</P>
<P><BR>Analysis:</P>
<P>Since we are changing the states of N-1 items each time, there is one coin which<BR>keeps its previous state.</P>
<P>1 --- 正面 (or *)<BR>0 --- 反面</P>
<P>1 1 1 1 (original state: #0)<BR>0 0 0 1 (#1 --- keeps N = 4)<BR>1 1 0 0 (#2 --- keeps N-1 = 3)<BR>0 1 1 1 (#3 --- keeps N-2 = 2)<BR>0 0 0 0 (#4 --- keeps N-3 = 1)</P>
<P>This is true for the general case N.</P>
<P><BR>Sample output:</P>
<P> * * * *<BR> 0 0 0 *<BR> * * 0 0<BR> 0 * * *<BR> 0 0 0 0<BR>Press any key to continue . . .</P>
<P>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <BR><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A><BR>*/</P>
<P><BR>#include <iostream><BR>#include <iomanip><BR>#include <vector><BR>using namespace std;</P>
<P>void print(const vector<bool>& v);<BR>int tossCoins(int n);</P>
<P><BR>int main(int argc, char** argv)<BR>{<BR> tossCoins(4);</P>
<P> return 0;<BR>}</P>
<P>int tossCoins(int n)<BR>{<BR> vector<bool> v;<BR> int i;<BR> int j;</P>
<P> // orginal state<BR> v.resize(n);<BR> for(i=0; i<n; ++i)<BR> v[i] = true;<BR> print(v);</P>
<P> for(i=n-1; i>=0; --i)<BR> {<BR> for(j=0; j<n; ++j)<BR> v[j] = !v[j];<BR> v[i] = !v[i]; // keeps v[i]</P>
<P> print(v);<BR> }</P>
<P> return n;<BR>}</P>
<P>void print(const vector<bool>& v)<BR>{<BR> for(vector<bool>::const_iterator iter = v.begin(); iter != v.end(); ++iter)<BR> {<BR> if(*iter)<BR> cout<<setw(4)<<"*";<BR> else<BR> cout<<setw(4)<<"0";<BR> cout<<" ";<BR> }<BR> cout<<endl;<BR>}<BR></P> [em09][em17] <P>/*---------------------------------------------------------------------------<BR>File name: C76-17.cpp<BR>Author: HJin<BR>Created on: 6/18/2007 18:21:10</P>
<P><BR>C76-17.cpp --- the cpp source file for solving the 17th of the 76<BR>classical C/C++ problems.</P>
<P>经典 76 道编程题 之 17:</P>
<P>17. 编写一个程序,当输入不超过60个字符组成的英文文字时,计算机将这个句子<BR> 中的字母按英文字典字母顺序重新排列,排列后的单词的长度要与原始句子中的长度<BR> 相同。例如:</P>
<P> 输入:</P>
<P> THE PRICE OFBREAD IS ¥1 25 PER POUND</P>
<P> 输出:</P>
<P> ABC DDEEE EFHIINO OP ¥1 25 PPR RRSTU</P>
<P> 并且要求只对A到Z的字母重新排列,其它字符保持原来的状态。</P>
<P> <BR>Analysis:</P>
<P>This is really a counting sort problem --- count how many letters A to Z.</P>
<P><BR>Sample output:</P>
<P>THE PRICe OFBREAD IS $1.25 PER POUND<BR>ABC DDEEE EFHIINO OP $1.25 PPR RRSTU<BR>Press any key to continue . . .</P>
<P><BR>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <BR><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A><BR>*/</P>
<P>#include <iostream><BR>#include <iomanip><BR>using namespace std;</P>
<P>/**<BR>counting sort to sort the letters 经典 76 道编程题 之 17.</P>
<P>Space complexity: O(1).<BR>Time complexity: O(strlen(s)).<BR>*/<BR>void counting_sort(char* s);</P>
<P>int main(int argc, char** argv)<BR>{<BR> char s[] = "THE PRICe OFBREAD IS $1.25 PER POUND";</P>
<P> cout<<s<<endl;</P>
<P> counting_sort(s);<BR> cout<<s<<endl;</P>
<P> return 0;<BR>}</P>
<P>void counting_sort(char* s)<BR>{<BR> /**<BR> c[0] --- stores how many letter A in s<BR> c[1] --- stores how many letter B in s<BR> ...<BR> c[25] --- stores how many letter Z in s<BR> */<BR> int c[26];<BR> int n =strlen(s);<BR> int i;<BR> int j;</P>
<P> // initiate counters to 0<BR> for(j=0; j<26; ++j)<BR> {<BR> c[j] = 0;<BR> }</P>
<P> for(i=0; i<n; ++i)<BR> {<BR> // toupper() does not affect non-alpha letters.<BR> s[i] = toupper(s[i]);<BR> }<BR> <BR> // count number of different capital letters<BR> for(i=0; i<n; ++i)<BR> {<BR> if(s[i] >='A' && s[i] <='Z')<BR> {<BR> j = 0+ (s[i] - 'A') ;<BR> ++c[ j ]; <BR> }<BR> }</P>
<P> i=0;</P>
<P> /**<BR> Although there are two loops here, it is NOT O(25* n).<BR> It is O(n), since i is incremented c[j] times for each j,<BR> and c[0] + c[1] + ... +c[25] <= n.<BR> */<BR> for(j=0; j<25; ++j)<BR> {<BR> while (c[j] > 0)<BR> {<BR> if(s[i]>='A' && s[i]<='Z')<BR> {<BR> s[i] = 'A'+j;<BR> --c[j]; // used 1 letter, so counter goes down by 1<BR> }<BR> ++i;<BR> }<BR> }<BR>}<BR></P> <P>哇~这么强啊!!!厉害[em17]</P> <P>/*---------------------------------------------------------------------------<BR>File name: C76-1.cpp<BR>Author: HJin<BR>Created on: 6/18/2007 22:53:55</P>
<P><BR>C76-1.cpp --- the cpp source file for solving the 1st of the 76<BR>classical C/C++ problems.</P>
<P>经典 76 道编程题 之 1:</P>
<P> 1. 给定等式 A B C D E 其中每个字母代表一个数字,且不同数字对应不<BR> D F G 同字母。编程求出这些数字并且打出这个数字的<BR> + D F G 算术计算竖式。</P>
<P> ───────</P>
<P> X Y Z D E</P>
<P><BR>Analysis:</P>
<P>Let A = a[0], B = a[1], ..., Z = a[9], where the array a<BR>is a permutation of the ten digits. The easist way is to<BR>loop over all 10! = 3,628,800 possible permutations for the array a,<BR>and check if the result holds.</P>
<P>C++ has a next_permutation (or prev_permutation) function template<BR>for permutations.</P>
<P><BR> A B C D E F G X Y Z<BR>==============================<BR>a[ 0 1 2 3 4 5 6 7 8 9 ]</P>
<P>Sample output:</P>
<P>A = 2, B = 9, C = 7, D = 8, E = 6,<BR>F = 5, G = 0, X = 3, Y = 1, Z = 4.</P>
<P> 2 9 7 8 6<BR> 8 5 0<BR>+ 8 5 0<BR>--------------------------------------<BR>= 3 1 4 8 6<BR>Press any key to continue . . .</P>
<P>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <BR><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A><BR>*/</P>
<P>#include <iostream><BR>#define DIM(x) sizeof((x)) / sizeof ( (x)[0] )<BR>#include <algorithm></P>
<P>using namespace std;</P>
<P>/**<BR>check the result for a permutation.<BR>*/<BR>bool check(int *a);</P>
<P>/**<BR>print result.<BR>*/<BR>void print(int *a);</P>
<P>int main(int argc, char** argv)<BR>{<BR> int a[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};<BR> bool res = check(a);<BR> if(res)<BR> print(a);</P>
<P> // when next_permutation returns false, we permute<BR> // all 10! choices. Time complexity is O(10!)<BR> while( std::next_permutation(a, a+DIM(a)) )<BR> {<BR> res = check(a);<BR> if(res)<BR> print(a);<BR> }</P>
<P> return 0;<BR>}</P>
<P>bool check(int *a)<BR>{<BR> int carry; // carry<BR> bool res;<BR> int temp;</P>
<P> // 1st vertical equation<BR> temp = a[4] + 2*a[6];<BR> res = ( ( temp % 10) == a[4] );<BR> if(!res)<BR> return false;<BR> carry = temp / 10;</P>
<P> // 2nd vertical equation<BR> temp = a[3] + 2*a[5] + carry;<BR> res = res && ( (temp % 10) == a[3] );<BR> if(!res)<BR> return false;<BR> carry = temp / 10;</P>
<P> // 3rd vertical equation<BR> temp = a[2] + 2*a[3] + carry;<BR> res = res && ( ( temp % 10) == a[9] );<BR> if(!res)<BR> return false;<BR> carry = temp / 10;</P>
<P> // 4th vertical equation<BR> temp = a[1] + carry;<BR> res = res && ( ( temp % 10) == a[8] );<BR> if(!res)<BR> return false;<BR> carry = temp / 10;</P>
<P> // 5th vertical equation<BR> temp = a[0] + carry;<BR> res = res && ( ( temp % 10) == a[7] );<BR> if(!res)<BR> return false;</P>
<P> return true;<BR>}</P>
<P>void print(int *a)<BR>{<BR> cout<<"A = "<<a[0]<<", ";<BR> cout<<"B = "<<a[1]<<", ";<BR> cout<<"C = "<<a[2]<<", ";<BR> cout<<"D = "<<a[3]<<", ";<BR> cout<<"E = "<<a[4]<<",\n";<BR> cout<<"F = "<<a[5]<<", ";<BR> cout<<"G = "<<a[6]<<", ";<BR> cout<<"X = "<<a[7]<<", ";<BR> cout<<"Y = "<<a[8]<<", ";<BR> cout<<"Z = "<<a[9]<<".\n\n";</P>
<P> cout<<" "<<a[0]<<" "<<a[1]<<" "<<a[2]<<" "<<a[3]<<" "<<a[4]<<"\n";<BR> cout<<" "<<a[3]<<" "<<a[5]<<" "<<a[6]<<"\n";<BR> cout<<"+ "<<a[3]<<" "<<a[5]<<" "<<a[6]<<"\n";<BR> cout<<"--------------------------------------\n";<BR> cout<<"= "<<a[7]<<" "<<a[8]<<" "<<a[9]<<" "<<a[3]<<" "<<a[4]<<"\n";<BR>}<BR></P> I just saw aipb2007's solution to #17 --- very clever. Although your space complexity is 2n, the algorithm is easy to follow. Time complexity is O(n lg n ), n = strlen(s) --- since you used a sort (the standard algorithm) which is a comparison sorting, which is necessarily eat least O(n lg n).<br><br>My soln is a little hard to understand for a beginner, but it uses only strlen(s) + const space and most importantly, time compelexity is only O(n).
[align=right][color=#000066][此贴子已经被作者于2007-6-21 5:56:20编辑过][/color][/align]
<P>第三题挑个简单的<BR><BR>#include "stdio.h"</P>
<P>main()<BR>{<BR> char s[21][21];<BR> char c[]={'T','J','1','2','3','4','5','6','7','8','9'};<BR> int input,i,j;<BR> printf("enter the number betweent 3 to 20");<BR> scanf("%d",&input);<BR> if(input<3||input>20)<BR> {<BR> printf("what you want ");<BR> getch();<BR> return;<BR> }<BR> for(i=0;i<=input;i++)<BR> {<BR> for(j=0;j<=input;j++)<BR> s[i][j]='0';</P>
<P> }<BR> for(i=0;i<=input;i++)<BR> {<BR> for(j=0;j<=input;j++)<BR> printf("%c",s[i][j]);<BR> printf("\n");<BR> }</P>
<P> for(i=input;i>=0;i--)<BR> {<BR> for(j=i;j<=input-i;j++)<BR> {<BR> s[j][i]=c[i];<BR> s[i][j]=c[i];<BR> s[input-i][input-j]=c[i];<BR> s[input-j][input-i]=c[i];<BR> }</P>
<P> }<BR> for(i=0;i<=input;i++)<BR> {<BR> for(j=0;j<=input;j++)<BR> printf("%c",s[i][j]);<BR> printf("\n");<BR> }<BR> getch();<BR>}</P> To HJin : <BR> Actually I know a little abt algorithms, but I'm really interesting in it. Most of these questions are base on an algorithm, I just found the way to get the answer, abt the efficiency, I didn't consider it.[em04]<BR><BR>Recently I have to prepare for the examination.So I have no time to do the subjects.I'll study algorithms during summer holiday. After that I think I can catch your step.[em02]<BR><BR>I will see all your solutions above when I come to the same subject.[em17]<BR> <P>/*---------------------------------------------------------------------------<BR>File name: C76-24.cpp<BR>Author: HJin<BR>Created on: 6/18/2007 22:53:55</P>
<P><BR>C76-24.cpp --- the cpp source file for solving the 24th of the 76<BR>classical C/C++ problems.</P>
<P>经典 76 道编程题 之 24:</P>
<P> 24. 某地街道把城市分割成矩形方格,每一方格叫作块,某人从家中出发上班,<BR> 向东要走M块,向北要走N块,(见图)。请设计一个程序,由计算机寻找并<BR> 打印出所有的上班的路径。</P>
<P> 单位</P>
<P> ┬ ┌─┬─┬─┬─┬─┬─┬─┐<BR> │ │ │ │ │ │ │ │ │<BR> │ ├─┼─┼─┼─┼─┼─┼─┤<BR> ↓ │ │ │ │ │ │ │ │<BR> N ├─┼─┼─┼─┼─┼─┼─┤<BR> ↑ │ │ │ │ │ │ │ │<BR> │ ├─┼─┼─┼─┼─┼─┼─┤<BR> │ │ │ │ │ │ │ │ │<BR> ┴ └─┴─┴─┴─┴─┴─┴─┘<BR> 家 ├─────→M←─────┤</P>
<P><BR>Analysis:</P>
<P>Let us<BR> <BR> E --- the person move 1km to the east;<BR> N --- to stand for the person move 1km to the east;</P>
<P>If M= 7, N =4 (as in the figure), then</P>
<P> E E E E E E E N N N N</P>
<P>means that the person travels east 7km first, then he/she travels<BR>north 4km.</P>
<P>A little bit math shows that we have</P>
<P> binomial(M+N, M)</P>
<P>different ways to travel from home to work, since we have to travel<BR>M kms to the east. A way is a choice that how we put the M E's into<BR>M+N slots.</P>
<P>Sample output (for M=5, N=2):</P>
<P>1 EEEEENN<BR>2 EEEENEN<BR>3 EEEENNE<BR>4 EEENEEN<BR>5 EEENENE<BR>6 EEENNEE<BR>7 EENEEEN<BR>8 EENEENE<BR>9 EENENEE<BR>10 EENNEEE<BR>11 ENEEEEN<BR>12 ENEEENE<BR>13 ENEENEE<BR>14 ENENEEE<BR>15 ENNEEEE<BR>16 NEEEEEN<BR>17 NEEEENE<BR>18 NEEENEE<BR>19 NEENEEE<BR>20 NENEEEE<BR>21 NNEEEEE<BR>correct.<BR>Press any key to continue . . .</P>
<P><BR>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <BR><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A><BR>*/</P>
<P>#include <iostream><BR>#include <string><BR>#include <set><BR>using namespace std;</P>
<P>/**<BR>serious improvment needed: this recursive version is very inefficient.<BR>For M=7, N=4, it takes 3 mintues to compute.</P>
<P>The classical algorithm to permute a string. We use a set to keep<BR>different strings --- some permutations may repeat.</P>
<P>*/<BR>void way_recursive(string& in, string& out, set<string>& ss);</P>
<P>/**<BR>a wrapper of way_recursive.<BR>*/<BR>int way(int M, int N, bool print=true);</P>
<P>/** compute binomial(n, k).<BR> * n >=k<BR> * <BR> * <BR> */<BR>int binomial(int n, int k); // n choose k</P>
<P><BR>int main(int argc, char** argv)<BR>{<BR> // test #1: --- the recursive way takes long time (3 mintues)<BR> //int M=7;<BR> //int N=4;</P>
<P><BR> // test #2:<BR> int M=5;<BR> int N=2;</P>
<P> int num;</P>
<P> num = way(M, N);</P>
<P><BR> /**<BR> A little bit math shows that the number is binomial(M+N, M).<BR> This is just a check to give you more confidence.<BR> */<BR> if(num != binomial(M+N, M))<BR> cout<<"wrong number.\n";<BR> else<BR> cout<<"correct.\n";</P>
<P> return 0;<BR>}</P>
<P>void way_recursive(string& in, string& out, set<string>& ss)<BR>{<BR> // in is empty so that all chars are transferred to out buffer<BR> // and out is a permutation of in<BR> if( in.empty() )<BR> {<BR> ss.insert(out); // insert only one copy --- no duplicates<BR> return;<BR> }</P>
<P> // the way to permute a string in one statement<BR> for(size_t i=0; i<in.size(); ++i)<BR> way_recursive(in.substr(0, i) + in.substr(i+1), out+in[i], ss);<BR>}</P>
<P>int way(int M, int N, bool print)<BR>{<BR> set<string> ss;<BR> string in;<BR> string out;<BR> int i;<BR> int counter = 0;</P>
<P> in.resize(M+N);<BR> <BR> // the very first way<BR> for(i=0; i<M; ++i)<BR> in[i] = 'E';<BR> for(i=M; i<M+N; ++i)<BR> in[i] = 'N';</P>
<P> // build the set<BR> way_recursive(in, out, ss);<BR> <BR> if(print)<BR> {<BR> for(set<string>::const_iterator iter = ss.begin(); iter != ss.end(); ++iter)<BR> {<BR> ++counter;<BR> cout<<counter<<"\t"<<*iter<<endl;<BR> }<BR> }</P>
<P> return counter;<BR>}</P>
<P>int binomial(int n, int k)<BR>{<BR> int res = 1;<BR> int i;</P>
<P> if(k>n/2)<BR> k = n-k;</P>
<P> ++n;<BR> for(i=1; i<=k; ++i)<BR> {<BR> res *= (n-i);<BR> res /= i;<BR> }</P>
<P> return res;<BR>}<BR></P> To everybody:<br> You are good example,I have learned so much from you . I am not good at arithmetic,so I have many things to learn.As aipb2007,I am plan to study arithmetic in the hoilday.Arithmetic is interesting,and I like it.<br> Exam is coming,I think you are prepareing for exam.so do I.Good luck!<br> At last,Happy Dragon Boat Festival!
[align=right][color=#000066][此贴子已经被作者于2007-6-19 17:20:02编辑过][/color][/align]
<P>Happy holiday to you! Admire you have "zhongzi"..... no Chinese food in this small town for me.</P> HJin...I 服了 You... 受我一拜.. orz<br><br>继续消化... To HJin :<br>Where are you? <P>都是高手啊。...参考参考</P>
[align=right][color=#000066][此贴子已经被作者于2007-6-20 13:18:05编辑过][/color][/align]
关于第一题给出另一种解法:<br><br>ABCDE + (DFG)*2 = XYZDE <=> (DFG)*2 = XYZDE - ABCDE <=> (XYZ - ABC)*100<br><=> DFG = (XYZ - ABC)*50 <br>由此可以看出,E可以取任何数字,只要其他的字母的组合有解。<br><br>下面是代码:<br> <br>[CODE]<br> #include <iostream><br>using namespace std;<br><br>int main()<br>{<br> int A, B, C, D, E, F, G, X, Y, Z;<br> int value1, value2, value3;<br> <br> cout<<"A B C D E F G X Y Z\n"; <br> for(A = 0; A<=8; A++)<br> {<br> for(X = A+1; X<=9; X++)<br> {<br> for(B = 0; B<=9; B++)<br> {<br> if(B==A || B==X)<br> continue;<br> for(C = 0; C<=9; C++)<br> {<br> if(C==A || C==X || C==B)<br> continue;<br> for(Y = 0; Y<=9; Y++)<br> {<br> if(Y==A || Y==X || Y==B || Y==C)<br> continue;<br> for(Z = 0; Z<=9; Z++)<br> {<br> if(Z==A || Z==X || Z==B || Z==C || Z==Y)<br> continue;<br> for(D = 0; D<=9; D++)<br> {<br> if(D==A || D==X || D==B || D==C || D==Y || D==Z)<br> continue;<br> for(F = 0; F<=9; F++)<br> {<br> if(F==A || F==X || F==B || F==C || F==Y || F==Z || F==D)<br> continue;<br> for(G = 0; G<=9; G++)<br> {<br> if(G==A || G==X || G==B || G==C || G==Y || G==Z || G==D || G==F)<br> continue;<br> value1 = X*100 + Y*10 + Z;<br> value2 = A*100 + B*10 + C;<br> value3 = D*100 + F*10 + G;<br> if(value3 == ((value1-value2)*50))<br> {<br> for(E = 0; E<=9; E++)<br> {<br> cout<<A<<" "<<B<<" "<<C<<" "<<D<<" "<<E<<" "<<F<<" "<<G<<" "<<X<<" "<<Y<<" "<<Z<<endl;<br> }<br> }<br> }<br> }<br> }<br> } <br> }<br> }<br> }<br> }<br> }<br> <br> system("pause");<br> return 0;<br>}<br><br>[/CODE]<br>这样的代码看上去笨了些,for loop 一个套一个,但是免去了很多的测试,效率应该高一些。<br> 有点意思.... 关于第二题,其实是数字电路的问题。5个条件就是第一层的5个门电路,将5个门电路的输出结果在第二层通过一个与门就可以得到最终的结果了。所以代码是很简单的,其中0表示不参加,1表示参加.<br><br>listing2.cpp<br>[CODE]<br>#include <iostream><br>using namespace std;<br><br>int main()<br>{<br> int A,B,C,D,E;<br> int out1, out2, out3, out4, out5;<br> int out;<br> cout<<"A B C D E\n";<br> for(A = 0; A<=1; A++)<br> {<br> for(B = 0; B<=1; B++)<br> {<br> for(C = 0; C<=1; C++)<br> {<br> for(D = 0; D<=1; D++)<br> {<br> for(E = 0; E<=1; E++)<br> {<br> out1 = (A&B) | (!A);<br> out2 = (!B) | (!C);<br> out3 = (C&D) | ((!C)&(!D));<br> out4 = D | E;<br> out5 = (E & A & D) | (!E);<br> out = out1 & out2 & out3 & out4 & out5;<br> if(out == 1)<br> cout<<A<<" "<<B<<" "<<C<<" "<<D<<" "<<E<<endl; <br> }<br> }<br> }<br> }<br> }<br> return 0;<br>}<br><br>[/CODE] <P>/*---------------------------------------------------------------------------<br>File name: C76-4.cpp<br>Author: HJin<br>Created on: 6/22/2007 19:33:55</P>
<P>Modification history:</P>
<P>6/23/2007 14:51:02<br>-----------------------------------------------------------<br>Apply a recursive technique to construct all Latin Squares of<br>size n<=6.</P>
<P>This recursive approach gives all the solutions, although it is<br>fairly slow due to the large number of solutions. For n=7, there<br>are 61,479,419,904,000 Latin squares. The number 61,479,419,904,000<br>overflows the integers for 32-bit system.</P>
<P>I consider this problem solved.</P>
<P><br>6/22/2007 22:34:40<br>-----------------------------------------------------------<br>First attack: generate n! Latin squares.</P>
<P>This iterative approach only gives a partial soln, but it is<br>fast.</P>
<P><br>C76-4.cpp --- the cpp source file for solving the 4th of the 76<br>classical C/C++ problems.</P>
<P><br>经典 76 道编程题 之 4:</P>
<P>4. 在N行N列的数阵中, 数K(1〈=K〈=N)在每行和每列中出现且仅<br>出现一次,这样的数阵叫N阶拉丁方阵。例如下图就是一个五阶拉丁方阵。<br>编一程序,从键盘输入N值后,打印出所有不同的N阶拉丁方阵,并统计个数。</P>
<P>1 2 3 4 5<br>2 3 4 5 1<br>3 4 5 1 2<br>4 5 1 2 3<br>5 1 2 3 4</P>
<P>Analysis:</P>
<P>This problem is fairly complex, as it is unsolved for the general case n.<br>For n<=10, I give the known number of different Latin squares in the<br>following table</P>
<P><br>n | # of Latin squares<br>----+------------------------------------------------------<br>1 | 1<br>2 | 2<br>3 | 12<br>4 | 576<br>5 | 161280<br>6 | 812851200<br>7 | 61479419904000<br>8 | 108776032459082956800<br>9 | 5524751496156892842531225600<br>10 | 9982437658213039871725064756920320000<br>11 | 776966836171770144107444346734230682311065600000<br>>11 | (no one knows the exact number)<br>----+------------------------------------------------------</P>
<P>If you want only partial solutions for a fairly large n, please check my</P>
<P> generate_iterative()</P>
<P>procedure, which is based on rotating a permuation of 1 2 ... n.</P>
<P>If you want all solutions for n<=6, please check my</P>
<P> generate_recursive()</P>
<P>procedure.</P>
<P><br>Sample output</P>
<P>(For test #1, n = 5, only 3 Latin squares are shown.) <br>Latin squares #161278<br> 5 4 3 2 1<br> 4 5 2 1 3<br> 3 2 1 4 5<br> 2 1 5 3 4<br> 1 3 4 5 2<br>Latin squares #161279<br> 5 4 3 2 1<br> 4 5 2 1 3<br> 3 2 1 5 4<br> 1 3 5 4 2<br> 2 1 4 3 5<br>Latin squares #161280<br> 5 4 3 2 1<br> 4 5 2 1 3<br> 3 2 1 5 4<br> 2 1 4 3 5<br> 1 3 5 4 2<br>There are 161280 different Latin Squares for n = 5<br>Press any key to continue . . .</P>
<P><br>(For test #2, n = 7, only 3 Latin squares are shown.)<br>Latin Square #5038<br> 7 6 5 4 2 3 1<br> 5 4 6 2 3 1 7<br> 6 2 4 3 1 7 5<br> 4 3 2 1 7 5 6<br> 2 1 3 7 5 6 4<br> 3 7 1 5 6 4 2<br> 1 5 7 6 4 2 3<br>Latin Square #5039<br> 7 6 5 4 3 1 2<br> 5 7 4 3 1 2 6<br> 4 5 3 1 2 6 7<br> 3 4 1 2 6 7 5<br> 1 3 2 6 7 5 4<br> 2 1 6 7 5 4 3<br> 6 2 7 5 4 3 1<br>Latin Square #5040<br> 7 6 5 4 3 2 1<br> 6 5 4 3 2 1 7<br> 5 4 3 2 1 7 6<br> 4 3 2 1 7 6 5<br> 3 2 1 7 6 5 4<br> 2 1 7 6 5 4 3<br> 1 7 6 5 4 3 2<br>Press any key to continue . . .</P>
<P>Reference:</P>
<P>1. 野比, 相当经典的76道编程自虐题分享.无答案 at <br><a href="http://bbs.bc-cn.net/viewthread.php?tid=147853" target="_blank" >http://bbs.bc-cn.net/viewthread.php?tid=147853</A></P>
<P>2. <a href="http://en.wikipedia.org/wiki/Latin_square" target="_blank" >http://en.wikipedia.org/wiki/Latin_square</A><br>*/</P>
<P>#include <iostream><br>#include <iomanip><br>#include <algorithm></P>
<P>using namespace std;</P>
<P><br>/** buffer for 2d array (n! x n)<br>This buffer stores all the n! permuations for 1 2 ... n.<br>You can use a set.</P>
<P>If you want to generate all the permuatations along the way,<br>you spend more time. My technique is sacrifice space in<br>favor of speed.<br>*/<br>int** g_AllPerms;<br>int g_nFact; // n!</P>
<P>/**<br>A recursive algorithm to get all the Latin squares of size n.</P>
<P>The number of different Latin squares of size n is stored in counter.</P>
<P>Space complexity: O( (n+1)! ).<br>Time complexity: O( (n+1)! ).</P>
<P>*/<br>void generate_recursive(int** a, int n, int numRSF, int& counter, bool print = false);</P>
<P><br>/**<br>This generator can only generate n! different Latin squares. Thus,<br>it is a partial soln.</P>
<P>I cannot describe the idea in plain text format, you may referr to reference 2<br>and google for "Latin square".</P>
<P>Space complexity: O( (n+1)! ).<br>Time complexity: O( (n+1)! ).<br>*/<br>void generate_iterative(int** a, int* buffer, int n, bool print=true);</P>
<P>/**<br>Rotate a sequence one position to the left. For example,</P>
<P>1 2 3 4 --> 2 3 4 1.<br>*/<br>void rotate(int *aPerm, int n);</P>
<P><br>/**<br>Check if the first numRSF rows of a matrix is valid for a Latin<br>square.</P>
<P>numRSF --- number of Rows So Far<br>*/<br>inline bool isValid(int**a, int n, int numRSF);</P>
<P>/**<br>Copy the content of a buffer to another.<br>*/<br>inline void copy(int*dest, int* src, int n);</P>
<P>/**<br>Compute the facotrial of n.<br>*/<br>inline int factorial(int n);</P>
<P>/**<br>auxilliary functions for 2d array dynamic allocation and deallocation.<br>*/<br>template <typename T><br>inline T** new2d(int row, int col);</P>
<P>template <typename T><br>inline void delete2d(T** arr2d, int row);</P>
<P><br>int main()<br>{<br> /**<br> All cases for n > 6 cannot be solved by the recursive version, using<br> 32-bit intergers.</P>
<P> If you use the iterative version, you can let n be fairly large.<br> */<br> int n=4;<br> int i;<br> int* buf; // buffer for 1d array of size n<br> int** a;<br> int counter = 0;</P>
<P> g_nFact = factorial(n);</P>
<P> buf = new int[n];<br> for(i=0; i<n; ++i)<br> {<br> buf[i] = i+1;<br> }</P>
<P> a = new2d<int>(n, n);<br> g_AllPerms = new2d<int>(g_nFact, n);</P>
<P> i=0;<br> copy(g_AllPerms[i], buf, n);<br> while(next_permutation(buf, buf+n))<br> {<br> ++i;<br> copy(g_AllPerms[i], buf, n);<br> }</P>
<P> // test #1 --- recursive (complete soln)<br> generate_recursive(a, n, 0, counter, true);<br> cout<<"There are "<<counter<<" different Latin Squares for n = "<<n<<endl;</P>
<P><br> // test #2 --- iterative (partial soln)<br> generate_iterative(a, buf, n);</P>
<P><br> delete [] buf;<br> delete2d<int>(a, n);<br> delete2d<int>(g_AllPerms, n);</P>
<P> return 0;<br>}</P>
<P>void generate_recursive(int** a, int n, int numRSF, int& counter, bool print)<br>{<br> // if all rows are filled<br> if(numRSF == n )<br> {<br> ++counter; // update counter</P>
<P> if(print) // print this Latin square<br> {<br> cout<<"Latin squares #"<<counter<<endl;<br> for(int i=0; i<n; ++i)<br> {<br> for(int j=0; j<n; ++j)<br> {<br> cout<<setw(4)<<a[i][j];<br> }<br> cout<<endl;<br> }<br> }</P>
<P> return;<br> }</P>
<P> for(int k=0; k<g_nFact; ++k)<br> {<br> for(int i=numRSF; i<n; ++i)<br> {<br> // fill in the current row<br> copy(a[i], g_AllPerms[k], n);</P>
<P> // if the matrix is valid up to row i<br> // then we fill in the next row<br> if(isValid(a, n, i))<br> generate_recursive(a, n, i+1, counter, print);<br> }<br> }<br>}</P>
<P>void generate_iterative(int** a, int* buf, int n, bool print)<br>{<br> int i;<br> int j;<br> int k;</P>
<P> for(k=0; k<g_nFact; ++k)<br> {<br> copy(buf, g_AllPerms[k], n);<br> for(i=0; i<n; ++i)<br> {<br> int value = g_AllPerms[k][buf[0]-1];</P>
<P> for(int j=0; j<n; ++j)<br> {<br> a[j][ buf[j]-1 ] = value;<br> }</P>
<P> rotate(buf, n);<br> }</P>
<P> // print the matrix<br> cout<<"Latin Square #"<<k+1<<endl;<br> for(i=0; i<n; ++i)<br> { <br> for(j=0; j<n; ++j)<br> {<br> cout<<setw(4)<<a[i][j];<br> }<br> cout<<endl;<br> }<br> }<br>}</P>
<P>void rotate(int *aPerm, int n)<br>{<br> int i;<br> int temp = aPerm[0];</P>
<P> for(i=0; i<n-1; ++i)<br> aPerm[i] = aPerm[i+1];</P>
<P> aPerm[n-1] = temp;<br>}</P>
<P>bool isValid(int**a, int n, int numRSF)<br>{<br> int i;<br> int j;</P>
<P> for(i=0; i<numRSF; ++i)<br> {<br> for(j=0; j<n; ++j)<br> {<br> if(a[i][j] == a[ numRSF ] [j])<br> {<br> return false;<br> }<br> }<br> }</P>
<P> return true;<br>}</P>
<P>void copy(int*dest, int* src, int n)<br>{<br> int i;</P>
<P> for(i=0; i<n; ++i)<br> dest[i] = src[i];<br>}</P>
<P>int factorial(int n)<br>{<br> int res = 1;</P>
<P> for(int i=2; i<=n; ++i)<br> res *= i;</P>
<P> return res;<br>}</P>
<P><br>template <typename T><br>T** new2d(int row, int col)<br>{<br> T** arr2d = new T*[row];<br> for(int i=0; i<row; ++i)<br> arr2d[i] = new T[col];</P>
<P> return arr2d;<br>}</P>
<P><br>template <typename T><br>void delete2d(T** arr2d, int row)<br>{<br> for(int i=0; i<row; ++i)<br> delete [] arr2d[i];</P>
<P> delete [] arr2d;<br>}<br></P>
[align=right][color=#000066][此贴子已经被作者于2007-6-24 7:23:26编辑过][/color][/align]
