1 某编程大赛题(35道题,中等难度)

1、在实际的开发工作中,对于string的处理是最常见的编程任务,本题是要求程序对用户输入的string进行处理,具体要求如下: 1、每个单词的首字母变为大写。 2、将数字与字母之间用下划线隔开,使结构清晰。 3、多个空格变为1个空格。 示例:输入:you and me what cpp2005pragram 则输出:You And Me What Cpp_2005_Program 输入:this    is    a  99cat 则输出:This Is  A 99_Cat*/

2* A,B,C,D,E,F,G,H,I,J,共10名学生有可能参加计算机竞赛,也可能不参加,因为某种原因他们受到下列条件的约束:1、 如果A参加,B也参加;   2、 如果C不参加,D也不参加;   3、 A和C中只能有1个人参加;   4、 B和D中有且仅有1个人参加;   5、 D、E、F、G、H 中至少有2人参加;   6、 C和G或者都参加,或者都不参加;   7、 C、E、G、I中至多只能2人参加      8、 如果E参加,那么F和G也都参加。   9、 如果F参加,G、H就不能参加   10、 如果I、J都不参加,H必须参加请编程根据这些条件判断10名同学参赛者名单比如LC D G J    代码在Num2里

3 *要求找出具有下列性质的数的个数(包含输入的自然数n): 先输入1个自然数n(n<=500),然后对此自然数按照如下方法进行处理: ①、 不作任何处理;②、 在它的左边加上1个自然数,但该自然数不能超过原数首位数字的1半; ③、 加上数后,继续按此要求进行处理,直到不能再加自然数为止、 样例:  输入:  6 满足条件的数为   6  16  26      126  36   136 输出:  6 */

private function fenjie(cnum: int, count: int , str: String): void{if(cnum == 0)return;if(count == max)trace(str);for (var i:int = cnum; i > 0; i--) {if(count + i > max)continue;fenjie(i, count +i, str + i);}}

/*巧排数字。将1、2、...、20这20个数排成1排,使得相邻的两个数之和为1个素数,且首尾两数字之和也为1个素数。编程打印出所有的排法。*/

有1楼房的楼梯级数很奇特,1步跨二级多1级,1步跨三级多二级,如果分用四、五、六、七去除级数分别余三、三、五、五。问这楼房共有多少级阶梯?(已知不超过400级)。

狼追兔子,兔子躲进了10个环形分布的洞的某1个中。狼在第1个洞中没有找到兔子,就间隔1个洞,到第3个洞中去找,也没找到兔子,就间隔2个洞,到第6个洞中去找。以后狼每次多隔1个洞去找兔子,……。这样狼1直找不到兔子。请问兔子可能躲在哪个洞中?

2、 1位数学家和1些游客共81人不幸落入强盗手中,强盗将俘虏排成1队,宣布每天处理所有第2的N次方个俘虏(N>=0),而只放走剩下的最后1个。由于数学家身怀重任,不得不选择了1个恰当的位置而最终被放走。请问他归初排在第几个位置。  3、 有1堆礼物,工作人员无论是分成二个1份,还是三个、四个、五个、六个1份,总是多1个。请问这堆礼物至少多少个? public class Test9 {public static void main(String[] args) {//求2、3、4、5、6的最小公倍数int i =7;while(true){if(i%2==1&&i%3==1&&i%4==1&&i%5==1&&i%6==1){System、out、println(i);break;}i=i+6;}}}

4、 1付扑克中拿出所有的黑桃A……K按顺序排好。第1次翻出第1张牌——A,放在1边,再拿出第2张放到牌的最下面。以后每次都翻出1张牌,再将1张牌放到最后,问第八次翻出的牌是哪1张?

public class Test10 {public static void main(String[] args) {String a[]={"A","2","3","4","5","6","7","8","9","10","J","Q","K"};List<String> list = new LinkedList<String>();int j;for (int i = 0; i < a、length; i++) {list、add(a[i]);}for ( j = 0; j < 7; j++) { list、remove(0);list、add(list、remove(0));}System、out、println(list、get(0));}}package test;/*2、 1位数学家和1些游客共81人不幸落入强盗手中,强盗将俘虏排成1队,宣布每天处理所有第2的N次方个俘虏(N>=0),而只放走剩下的最后1个。由于数学家身怀重任, 不得不选择了1个恰当的位置而最终被放走。请问他归初排在第几个位置。*/public class Test8 { /** * @param args */public static void main(String[] args) {// TODO Auto-generated method stubint a[] = new int[81];for (int i = 0; i < a、length; i++) {a[i] = i + 1;}// int b[] = a;int j = 0; int count = 0;while (count !=1) {count=0;for (int i = 0; i <= 6; i++) {a[(int) (Math、pow(2, i)) 1] = 0;// System、out、println((int)Math、pow(2, i)); }for (int i = 0; i < a、length; i++) { j=i;if (a[i] == 0) {for (int k = j + 1; k < a、length; k++) {if (a[k] != 0) {a[i] = a[k];a[k]=0; // j = k;// System、out、println("a["+i+"]="+a[i]+" "+"a["+k+"]="+a[k]);break;}}}}for (int i = 0; i < a、length; i++) {if(a[i]!=0)count++;}}for (int i = 0; i < a、length; i++) {if (a[i] != 0)System、out、println(a[i]);}} }

package test; import java、util、Arrays;import java、util、Scanner; /*验证卡布列克常数,对于1个四位数N,进行下列运算:(1)将组成该四位数的4个数字由大到小排列,形成由这4个数字组成的最大的四位数; (2)将组成该四位数的4个数字由小到大排列,形成由这4个数字组成的最小的四位数(如果高位为0则取得的数不足4位); (3)求两个数的差,得到1个新的四位数(高位0保留),称为对N进行了1次卡布列克运算。有这样的规律: 对1个各位数字不全相同的四位数重复进行若干次卡布列克运算,最后得到的结果总是6174。这个数被称为卡布列克常数。N从键盘输入。 输出每1次的卡布列克运算及得到6174时的运算次数。*/public class Test11 {private static int count = 0; public static void main(String[] args) {Scanner sc = new Scanner(System、in);System、out、println("请输入1个不完全相同的四位数");String str = sc、nextLine();char c1[] = str、toCharArray();verify(c1);Arrays、sort(c1);String strMin = String、copyValueOf(c1);String strMax = "";for (int i = c1、length - 1; i >= 0; i--) {strMax = strMax + c1[i];}// System、out、println(strMax+" "+strMin);int max = Integer、parseInt(strMax);int min = Integer、parseInt(strMin);System、out、println("max=" + max + " " + "min=" + min);kablk(strMax, strMin);} public static void verify(char[] c) {if (c、length < 4 || c、length > 4) {System、out、println("长度不符合要求");System、exit(0);}boolean flag = true;for (int i = 0; i < c、length - 1; i++) {if (c[i] != c[i + 1]) {flag = false;break;}}if (flag) {System、out、println("四位数完全相等");}} public static void kablk(String strMax, String strMin) {count++;int max = Integer、parseInt(strMax);int min = Integer、parseInt(strMin);int temp = max - min;if (temp == 6174) {System、out、println("count="+count);} else if (temp > 0) { char c1[] = String、valueOf(temp)、toCharArray();Arrays、sort(c1);strMin = String、copyValueOf(c1);for (int i = c1、length ; i < 4; i++) {strMin = "0" + strMin;}c1 = strMin、toCharArray();// System、out、println(c1);min = Integer、parseInt(strMin);strMax = "";for (int i = c1、length - 1; i >= 0; i--) {strMax = strMax + c1[i];// System、out、println(c1[i]);}max = Integer、parseInt(strMax);kablk(strMax, strMin);System、out、println("max=" + max + " " + "min=" + min);} else {return;} }}

编1程序,从键盘输入数字R,计算机自动检查在下列算式的“()”中能否填上“+”或“-”号凑成相应的等式。如能凑成,则打印出这些算式。如不能则打印“NO ANSWER”。     1( )2( )3( )4( )5( )6( )7( )8( )9=R

“百钱买百鸡”是我国古代的著名数学题。题目这样描述:3文钱可以买1只公鸡,2文钱可以买1只母鸡,1文钱可以买3只小鸡。用100文钱买100只鸡,那么各有公鸡、母鸡、小鸡多少只?与之相似,有"鸡兔同笼"问题。

判断1string是否是回文数,如121、12321、ABA等(string输入时以‘、’结束)。如输入:12321、输出:yes

找数。1个三位数,各位数字互不相同,十位数字比个位、百位数字之和还要大,且十位、百位数字之和不是质数。编程找出所有符合条件的三位数。     注:1、 不能手算后直接打印结果。     2、 “质数”即“素数”,是指除1和自身外,再没有其它因数的大于1的自然数。

选人。1个小组共五人,分别为A、B、C、D、E。现有1项任务,要他们中的3个人去完成。已知:(1)A、C不能都去;(2)B、C不能都不去;(3)如果C去了,D、E就只能去1个,且必须去1个;(4)B、C、D不能都去;(5)如果B去了,D、E就不能都去。编程找出此项任务该由哪三人去完成的所有组合。 李润伟(22048303) 17:45:55 截数问题: 任意1个自然数,我们可以将其平均截取成三个自然数。示例自然数135768,可以截取成13,57,68三个自然数。如果某自然数不能平均截取(位数不能被3整除),可将该自然数高位补零后截取。现编程从键盘上输入1个自然数N(N的位数<12),计算截取后第1个数加第三个数减第2个数的结果。

试编程找出能被各位数字之和整除的1切两位数

1个正整数的个位数字是6,如果将个位数字移到首位,所得到的数是原数的4倍,试编程找出满足条件的最小正整数。

某本书的页码从1开始,小明算了算,总共出现了202个数1,试编程求这本书1共有多少页?

有30个男人女人和小孩同在1家饭馆进餐,共花了五十先令,其中男宾3先令,女宾2先令,小孩1先令。试编程求出男人女人小孩各多少人?

编程找出四个互不相等的自然数, 它们之中任意两数之和为偶数,  任意三数之和可以被3整除, 而且这四个数的和越小越好(已知它们的和不大于50)、

以不同的字母代表0--9之间的数字, 现有如下等式成立: a+bc+def=ghij,编程求出满足上述条件等式的个数并将所有等式打印输出、

下面的竖式表示, 图中的"*"号只能用素数2,3,5,7代替, 因此称为素数乘法竖式、       * * *     × * *       ---------------       * * * *    * * * *        ----------------    * * * * *

1个四位数是1个完全平方数,减去1个每位数字都相同的四位数( 如 1111, 5555)后, 仍是1个完全平方数、 请编程打印出所有这样的四位数、

有1个八位数12345679, 若它乘以9, 则得九位数111111111, 试求:素数   (1)当这个数乘以什么数时, 才能得到全部由5所组成的九位数?   (2)当这个数乘以什么数时, 才能得到全部由9所组成的九位数?

李先生和他的孙子同出生于20世纪, 他的孙子与他的年龄之差为60岁,  李先生和他的孙子出生年份被3,4,5,6除, 余数分别为1,2,3,4、 编程求出李先生和他的孙子各出生在哪1年、

16/64是1个分子和分母都是两位数的真分数, 且分子的个位数与分母的十位数相同、 非常奇怪的是: 如果将该分数的分子的个位数和分母的十位数同时划去, 所得到的结果正好等于原分数约分后的结果、 例 16/64=1/4、 编程找出所有满足上述条件的真分数、

甲去买东西, 要付给乙19元, 而甲只有3元1张的钱, 乙只有5元1张的钱、  请为他们设计1个交换方案、

有六箱货物,重分别是5吨、2吨、3、5吨、1、7吨、1吨、5、1吨。现有1台货车,载重量10吨。设计1个程序,使这次车运走的货物最多。

某电台组织1次智力竞赛,计划安排奖励30人。准备了50件奖品。得1等奖者可得3件,二等奖2件,三等奖1件。希望将所有奖品都发到获奖者手中。请找出所有方案(即各等奖各有多少人)。

1个自然数是素数, 且它的数字位置经过任意对换后仍为素数, 称为绝对素数、  示例 13、  试找出所有这样的四位绝对素数

1个自然数, 若它的质因数至少是两重的(相同的质因数至少个数为二个, 如36=2*2*3*3)则称该数为"漂亮数"、  若相邻两个自然数都是"漂亮数", 就称它们为"孪生漂亮数"、 示例8与9就是1对、 请编程再找出1对"孪生漂亮数"。

某本书的页码从1开始,小明算了算,总共出现了202个数1,试编程求这本书1共有多少页?

public class Test3 {

/**

* @param args

*/

public static void main(String[] args) {

// TODO Auto-generated method stub

char buf[] = { 'a', 'b', 'c'};

int k = buf、length; // 选择几个字母排序

// char r[] = new char[k];

perm(0, buf, k); // 开始的字母在start,几个字母为k

}

public static void perm(int start, char[] buf, int k) {

if (start == k) { // 1个字母的全排列

for (int i = 0; i < k; i++) {

System、out、print(buf[i]);

}

System、out、println();

} else if (start < k) {// 多个字母全排列

for (int i = start; i < k; i++) {

char temp = buf[start]; // 交换数组的第1个元素和后续元素

buf[start] = buf[i];

buf[i] = temp;

perm(start + 1, buf, k); // 后续元素全排列

temp = buf[start]; // 还原

buf[start] = buf[i];

buf[i] = temp;

System、out、println("buf[start]="+buf[start]+" buf[i]="+buf[i]);

System、out、println("start="+start+" i="+i);

}

} else {

return;

}

}

}

任意输入二个自然数, 若商为整数, 则直接显示商; 否则将商分解成1个自然数和1个正的既约真分数之和才显示。 示例: 输入: 9, 3   显示: 9/3=3

          输入: 8, 6   显示: 8/6=1+1/3

任意输入四个自然数a,b,c,d, 看成二个分数a/b, c/d、 求这二个分数之和、  和的显示格式为: 输入 3,2,1,6    输出:  3/2+1/6=1+2/3。

在自然数中, 各位数字之和的11倍正好等于自身的自然数只有1个、 请找出这个自然数。

求所有不超过1000的这样的整数, 它的平方的末二位数字相同但不为0

Ecol<ecol0408@gmail、com>  9:51:18

package today;

import java、util、ArrayList;

import java、util、List;

public class help13 {

static List<Integer> count = new ArrayList<Integer>();

static boolean function(int num) {

for(int i=0;i<10000;i++){count、add(0);}

boolean bl = false;

int i = 2;

while (num > 1) {

if (num % i == 0) {

count、set(i-1,count、get(i-1)+1);

num /= i;

i = 2;

} else {

i++;

}

}

for (int k = 0; k < count、size(); k++) {

if (count、get(k) <2&&count、get(k)>0) {

//bl = true;

break;

}

if(k==count、size() 1){bl=true;}

}

count = null;

count = new ArrayList<Integer>();

return bl;

}

public static void main(String[] args) {

for (int i = 3; i <= 9999; i++) {

if (function(i) && function(i + 1)) {

System、out、println(i);

}

}

}

}

package test;

//1个正整数的个位数字是6,如果将个位数字移到首位,所得到的数是原数的4倍,试编程找出满足条件的最小正整数

public class Test16 {

public static void main(String[] args) {

// TODO Auto-generated method stub

String str = "";

int n = 0, m = 0;

int count = 1;

while (true) {

n = (int) Math、pow(10, count) + 6; //初始化为16,106,1006,10006,。。。。

for (int i = 1; i < 3;) {

str = String、valueOf(n);

String temp = str、substring(0, str、length() - 1);

str = str、substring(str、length() - 1) + temp;

m = Integer、valueOf(str);

if (m==n*4) {

System、out、println(n + " " + m);

System、exit(0);

}

n = n + 10;

i = (int) (n / Math、pow(10, str、length() - 1));//判断首位是否超过2

}

count++;

}

}

}

P是1个大于3的质数, 对某个自然数N, PN恰好是五位数,  且至少有三个位上的数字相同, 求P至少是多少。

编程求最小正整数M,N(0<N<M)为何值时, 1989m与1989n的最后三位数字相同

验证下面结论: 1个各位数字不同且都不为0的N位数X(3<=N<=5), 将组成该数的各位数字重新排列成1个最大数和1个最小数作减法, 其差值再重复前述运算, 若干次后必出现1个N位数Y, 使之重复出现、

示例: X=213, 则有 213→321-123=198     

      981-189=892

       982-289=693

       963-369=594

       954-459=495

       954-459=495

这时Y=954、

package test;

import java、util、Scanner;

/*任意输入二个自然数, 若商为整数, 则直接显示商; 否则将商分解成1个自然数和1个正的既约真分数之和才显示。 示例: 输入: 9, 3   显示: 9/3=3

输入: 8, 6   显示: 8/6=1+1/3*/

public class Test17 {

public static void main(String[] args) {

int a, b, n, m, l;

Scanner sc = new Scanner(System、in);

System、out、println("a=");

a = sc、nextInt();

System、out、println("b=");

b = sc、nextInt();

n = a / b; // 商的整数部分

m = a % b;// 余数

if (m != 0) // 不为0

{

l = Gcd(m, b); // 求出余数与被除数的最大公约数

m = m / l; // 分子;

b = b / l; // 分母

System、out、println(a + "/" + b + "=" + n + "+" + m + "/" + b);

} else

System、out、println(a + "/" + b + "=" + n);

}

static int Gcd(int m, int n) {

if (n == 0)

return m;

else

return Gcd(n, m % n);

}

}

任给1个自然数n,求出这个自然数不同因数的个数M

给出1个数n的不同因数个数m,求最小满足要求的自然数n,即n有m个不同的因数。

示例输入  2   则输出  2 因为2有2个因数。

m,n为自然数,其上限为k,试编写程序,由键盘输入自然数k找出满足条件:

(n^2-mn-m^2)^2=1 且使m^2+n^2达到最大的m,n。

输出能被11整除且不含重复数字的三位数。并统计个数。

已知1个四位数为ABCD,若A+C和B+D的值相等,则称这个四位数为交叉数,求四位数的交叉数和个数。

定义

  2x6=12   2和6的积是12,因此2和6是12的因数。12是2的倍数,也是6的倍数。   3x4=12   3和4也是12的因数。12是3和4的倍数。   整数A乘以整数B得到整数C,整数A与整数B就称做整数C的因数,反之整数C就为整数A与整数B的倍数。

package eclip;

/*在自然数中, 各位数字之和的11倍正好等于自身的自然数只有1个、 请找出这个自然数。*/

public class Test4 {

public static long check(long num){

long temp=num;

long sum=0;

while(temp!=0){

sum+=temp%10;

temp=temp/10;

}

return sum*11;

}

public static void main(String[] args) {

long num=1;

while(true){

if(check(num)==num){

System、out、println(num);

break;

}

num++;

}

}

}

P是1个大于3的质数, 对某个自然数N, PN恰好是五位数,  且至少有三个位上的数字相同, 求P至少是多少。

package ecol;

/*小明的妈妈是负责分发全厂工资的。

为使分发时有足够多的零钞,同时又

尽量不使每个人领到的钱太零碎。每

个月她都要计算出各种面值的钞票(

100元、50元、10元、5元、2元、1元,

假设每个人的工资都是整数元)各需要多少张

。你能否为她设计1个程序,从键盘输入10个人

的工资,再计算出各种面值的钞票各需要多少张?*/

public class mony {

static void function(int num){

int array[]=new int[5];

array[0]=100;

array[1]=50;

array[2]=10;

array[3]=5;

array[4]=2;

System、out、print(num+" = ");

for(int i=0;i<array、length;i++){

if(num/array[i]>0){System、out、print(num/array[i]+"*"+array[i]+(num%array[i]>0?"+":""));}

num%=array[i];

}

if((num/1)>0){System、out、println(num/1+"*"+1);}

}

public static void main(String[] args) {

function(12345);

}

}

输入1个string,将其中重复偶数次字符个数n,变为n/2,将重复奇数次字符个数m(m>=3),变为3*m+1,直到n=1,m=1,全部停止,输出每次做的1轮奇偶变化的string,示例:“gooddd”:

godddddddddd,goddddd,god、、、、d(16个d),godddddddd,godddd,godd,god

有1根长为514CM的钢筋,现在要截成23CM、15CM和19CM的短料,问在各至少截1根的前提下,问各截多少根,使所剩余料最少

package ecol;

import java、util、Scanner;

public class math {

static boolean function(int num){

boolean bl=false;int i;

for(i=2;i<=(int)Math、sqrt(num);i++){

if(num%i==0){break;}

}

if(i>(int)Math、sqrt(num)){bl=true;}

return bl;

}

static boolean function1(int num){

boolean bl=false;

int[]array=new int[10];

String str=""+num;

for(int i=0;i<str、length();i++){

array[Integer、parseInt(str、substring(i,i+1))]++;

}

for(int i=0;i<10;i++){

if(array[i]>=3){bl=true;break;}

}

return bl;

}

public static void main(String[] args) {

Scanner in=new  Scanner(System、in);

int N=in、nextInt();

for(int i=10000;i<=99999;i++){

if(i%N==0&&function(i/N)&&function1(i)){System、out、println(i/N);break;}

}

}

}

随意生成10个整数(20以内,不重复,随机位置),每个数加上它所存储位置的下标的和为质数:

1、如果这10个整数,满足条件的超过5个,就输出

2、如果改为10以内的数,请输出满足条件的个数和整数排列

求能被11整除,且不含重复数字的三位数?有多少个,并输出(注重算法效率)

求2~1000中的完数,(因子和等于它本身的数为完数。示例28的因子是1,2,4,7,14,且1+2+4+7+14=28,则28是完数)。

找2~1000中的亲密数对(如果A 的因子和等于B,B的因子和等于A,且A不等于B,则称A,B为亲密数对)。

有1个三位数,三个数字和为20,第三个数 3倍与第2个数的2倍及第1个数三者之和为44,第1个数与第2个数和的2倍减去第三个烽的4倍为-14,求这个三位数。

父子二人,已知儿子年龄不大于40岁,父亲年龄不大于100岁,10年前父亲的年龄是儿子年龄的4倍,10年后父亲的年龄是儿子年龄的整数倍。问父子现年多少岁

纯粹素数是这样定义的:1个素数,去掉最高位,剩下的数仍为素数,再去掉剩下的数的最高位,余下的数还是素数。这样下去1直到最后剩下的个位数也还是素数。求出所有小于3000的四位纯粹素数。

求n个最小的连续合数。合数是除了1和本身以外还有其它因子的正整数。

输入样例:3

输出样例: 8 9 10

大家熟知鸡兔同笼问题,输入两个数a,b,a为脚的只数,b为头的个数。编程序输出鸡的只数和兔的只数。

求圆周率π≈1-1/3+1/5-1/7+…+(-1)n-11/(2n-1),求π的近似值,真到某项的绝对值小于10-6为止

编写出打印出右边数字方阵的程序。

1 2 3 4 5 6

2 3 4 5 6 7

3 4 5 6 7 8

5 6 7 8 9 10

6 7 8 9 10 11

找出1~100之间的全部“同构数”。“同构数”是这样1种数:它出现在它的平方数的右端。示例:5的平方是25,5就是同构数,25也是构数。

用筛法求1 到10000的素数

有从1到n依次编号的n个人和n盏灯。我号人将所有的灯都关掉;2号人将编号为2的倍数的灯都打开;3号人则将编号为3的倍数的灯作相反处理;以后的人都将凡是自己编号的倍数的灯作相反处理。问第n个人操作后,哪些灯是打开的?

运动会连续开了n天,1共发了m枚奖章,第1天发1枚并剩下(m-1)枚的1/7,第2天发2枚并剩下的1/7,以后每天按此规律发奖章,在最后1天即第n天发了剩下的n枚奖章。问运动会开了多少天?1共发了几枚奖章?

设有1个数组A:array [0、、N-1] of integer; 存放的元素为0~N-1(1<N<=10)之间的整数,且A[i]≠A[j](i≠j)。示例当N=6时,有:A=(4,3,0,5,1,2)。此时,数组A的编码定义如下:

A[0]编码为0;

A[i]编码为:在A[0],A[1],…,A[i-1]中比A[i]的值小的个数

  (i=1,2,…,N-1)

∴上面数组A的编码为:B=(0,0,0,3,1,2)

要求编程解决以下问题:

(1)给出数组A后,求出其编码;

(2)给出数组A的编码后,求出A中的原数据

程序样例:

例1:

输入:Stat=1   {表示要解决的第(1)问题}

   N=8  {输入8个数}

   A=1 0 3 2 5 6 7 4

输出:B=0 0 2 2 4 5 6 4

例二:

输入:Stat=2   {表示要解决的第(2)问题}

   N=7

   B=0 1 0 0 4 5 6

输出:A=2 3 1 0 4 5 6

矩阵相乘:已知N×M1矩阵A和M1×M矩阵B(1≤M、M1、N≤10),求矩阵C(=A×B)。示例:

输入:N,M1,M=4  3  4

  A= 1   2    3  

3     4    5     提示:所谓矩阵相乘(如A×B=C),是指

4     5    6    Cij= ∑(Aik×Bkj)(i=1~N,j=1~M1,k=1~M)

5     –1  –2   

   B= 1   6    4    2    示例:

      2   3    4    1     C11=A11×B11+A12×B21+A13×B31

    –1   5    7   –3      =1×1+2×2+3×(– 1)

输出:C= 2   27   33   –5     =2

     6   55   63   –5    C42= A41×B12+A42×B22+A43×B32

     8   69   78   –5      =5×6+(–1)×3+(–2)×5

     5   17   2    15   =17

输入N(2≤N≤100)个数字(在0与9之间),然后统计出这组数中相邻两数字组成的链环数字对出现的次数。示例:

输入:N=20  {表示要输入数的数目}

  0  1  5  9  8  7  2  2  2  3  2  7  8  7  8  7  9  6  5  9

输出:(7,8)=2 (8,7)=3 {指(7,8)、(8,7)数字对出现次数分别为2次、3次)

 (7,2)=1 (2,7)=1

 (2,2)=2

 (2,3)=1 (3,2)=1

生成1个按蛇形方式排列自然数1,2,3,4,5,……,N2的 (1<N≤10)阶方阵。示例:

输入:N=4     N=7

输出: 1   3    4   10   1    3    4   10   11   21   22

   2   5    9   11   2    5    9   12   20   23   34

   6   8   12   15   6    8   13   19   24   33   35

   7   13  14   16   7   14   18   25   32   36   43

        15   17   26   31   37   42   44

        16   27   30   38   41   45   48

        28   29   39   40   46   47   49

2 各大IT公司招录算法题(120道,难度不分级)

1、题目描述:

对输入的n个数进行排序并输出。

输入:

输入的第1行包括1个整数n(1<=n<=100)。

接下来的1行包括n个整数。

输出:

可能有多组测试数据,对于每组数据,将排序后的n个整数输出,每个数后面都有1个空格。

每组测试数据的结果占1行。

样例输入:

4

1 4 3 2

样例输出:

1 2 3 4

#include <iostream>

#include <vector>

#include <algorithm>

using namespace std;

int main()

{

 int n;

 while(cin>>n&&n>=1&&n<=100)

 {

  vector<int> ivec;

  int itemp;

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

  {

   cin>>itemp;

   ivec、push_back(itemp);

  }

  sort(ivec、begin(),ivec、end());

  for(vector<int>::iterator j=ivec、begin();j!=ivec、end();j++)

   cout<<*j<<' ';

  cout<<endl;

 }

 return 0;

}

2、有N个学生的数据,将学生数据按成绩高低排序,如果成绩相同则按姓名字符的字母序排序,如果姓名的字母序也相同则按照学生的年龄排序,并输出N个学生排序后的信息。

输入:

测试数据有多组,每组输入第1行有1个整数N(N<=1000),接下来的N行包括N个学生的数据。

每个学生的数据包括姓名(长度不超过100的string)、年龄(整形数)、成绩(小于等于100的正数)。

输出:

将学生信息按成绩进行排序,成绩相同的则按姓名的字母序进行排序。

然后输出学生信息,按照如下格式:

姓名 年龄 成绩

样例输入:

3

abc 20 99

bcd 19 97

bed 20 97

样例输出:

bcd 19 97

bed 20 97

abc 20 99

#include<stdio、h>

#include<string、h>

struct student

{

 char name[101];

 int age;

 int score;

};

int main()

{

 int n,i,j;

 struct student a[1000],temp;

 while(scanf("%d",&n)!=EOF)

 {

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

  {

   scanf("%s %d %d",&a[i]、name,&a[i]、age,&a[i]、score);

  }

  for(i=1;i<n;i++)

  {

   for(j=1;j<=n-i;j++)

   {

    if(a[j-1]、score>a[j]、score)

    {

     temp=a[j-1];

     a[j-1]=a[j];

     a[j]=temp;

    }

    else if(a[j-1]、score==a[j]、score)

    {

     if(strcmp(a[j-1]、name,a[j]、name)>0)

     {

      temp=a[j-1];

      a[j-1]=a[j];

      a[j]=temp;

     }

     else if(strcmp(a[j-1]、name,a[j]、name)==0)

     {

      if(a[j-1]、age>a[j]、age)

      {

       temp=a[j-1];

       a[j-1]=a[j];

       a[j]=temp;

      }

     }

    }

   }

  }

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

  {

   printf("%s %d %d\n",a[i]、name,a[i]、age,a[i]、score);

  }

 }

 return 0;

}

4、 题目描述:

输入1系列整数,将其中最大的数挑出,并将剩下的数进行排序。

输入:

输入第1行包括1个整数N,1<=N<=1000,代表输入数据的个数。

接下来的1行有N个整数。

输出:

可能有多组测试数据,对于每组数据,

第1行输出1个整数,代表N个整数中的最大值,并将此值从数组中去除,将剩下的数进行排序。

第2行将排序的结果输出。

样例输入:

4

1 3 4 2

样例输出:

4

1 2 3

#include <stdio、h>

int main(){

int i,n,t,j,a[1000];

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

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

  scanf("%d",&a[i]);

  t=a[i];

  j=i-1;

  while(j>=0&&a[j]>t) {a[j+1]=a[j];j--;}

  a[j+1]=t;

 }

printf("%d\n",a[n-1]);

if(n==1) printf("-1\n");

else for(i=0;i<n-1;i++){

 printf("%d",a[i]);

 if(i!=n-2) printf(" ");

 else printf("\n");}

}

return 0;

}

5、 题目描述:

Excel可以对1组纪录按任意指定列排序。现请你编写程序实现类似功能。

对每个测试用例,首先输出1行“Case i:”,其中 i 是测试用例的编号(从1开始)。随后在 N 行中输出按要求排序后的结果,即:当 C=1 时,按学号递增排序;当 C=2时,按姓名的非递减字典序排序;当 C=3

时,按成绩的非递减排序。当若干学生具有相同姓名或者相同成绩时,则按他们的学号递增排序。

输入:

测试输入包含若干测试用例。每个测试用例的第1行包含两个整数 N (N<=100000) 和 C,其中 N 是纪录的条数,C 是指定排序的列号。以下有N行,每行包含1条学生纪录。每条学生纪录由学号(6位数字,同组测试中没有重复的学号)、姓名(不超过8位且不包含空格的string)、成绩(闭区间[0, 100]内的整数)组成,每个项目间用1个空格隔开。当读到 N=0 时,全部输入结束,相应的结果不要输出。

输出:

对每个测试用例,首先输出1行“Case i:”,其中 i 是测试用例的编号(从1开始)。随后在 N 行中输出按要求排序后的结果,即:当 C=1 时,按学号递增排序;当 C=2时,按姓名的非递减字典序排序;当 C=3

时,按成绩的非递减排序。当若干学生具有相同姓名或者相同成绩时,则按他们的学号递增排序。

样例输入:

3 1

000007 James 85

000010 Amy 90

000001 Zoe 60

4 2

000007 James 85

000010 Amy 90

000001 Zoe 60

000002 James 98

4 3

000007 James 85

000010 Amy 90

000001 Zoe 60

000002 James 90

0 0

样例输出:

Case 1:

000001 Zoe 60

000007 James 85

000010 Amy 90

Case 2:

000010 Amy 90

000002 James 98

000007 James 85

000001 Zoe 60

Case 3:

000001 Zoe 60

000007 James 85

000002 James 90

000010 Amy 90

#include <iostream>

#include <fstream>

#include <string>

#include <algorithm>

using namespace std;

struct info{

 string id;

 string name;

 int score;

};

bool cmp_id(const struct info a,const struct info b)

{

 return a、id<b、id;

}

bool cmp_name(const struct info a,const struct info b)

{

 if(a、name==b、name)

 return a、id<b、id;

 else

 return a、name<b、name;

}

bool cmp_score(const struct info a,const struct info b)

{

 if(a、score==b、score)

 return a、id<b、id;

 else

 return a、score<b、score;

}

int main(int argc, char **argv)

{

//ifstream cin("input、txt");

 int n,c,count=0;

 while(cin>>n>>c)

 {

  if(n==0&&c==0)

  break;

  count++;

  struct info data[n];

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

  cin>>data[i]、id>>data[i]、name>>data[i]、score;

  switch(c)

  {

   case 1:

   sort(data,data+n,cmp_id);

   break;

   case 2:

   sort(data,data+n,cmp_name);

   break;

   case 3:

   sort(data,data+n,cmp_score);

  }

  printf("Case %d:\n",count);

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

   printf("%s %s %d\n",data[i]、id、c_str(),data[i]、name、c_str(),data[i]、score);

  } 

}

6、题目描述:

输入1个string,长度小于等于200,然后将输出按字符顺序升序排序后的string。

输入:

测试数据有多组,输入string。

输出:

对于每组输入,输出处理后的结果。

样例输入:

bacd

样例输出:

Abcd

#include<stdio、h>

#include<string、h>

int main()

{

 char string[200],temp;

 int i,j,n;

 while(scanf("%s",string)!=EOF)

 {

  n=0;

  while(string[n])

  {

   n++;

  }

  for(i=1;i<n;i++)

  {

   for(j=0;j<n-i;j++)

   {

    if((string[j]-string[j+1])>0)

    {

     temp=string[j];

     string[j]=string[j+1];

     string[j+1]=temp;

    }

   }

  }

  printf("%s\n",string);

 }

 return 0;

}

7、 题目描述:

有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天

输入:

有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD

输出:

每组数据输出1行,即日期差值

样例输入:

20110412

20110422

样例输出:

11

#include<stdio、h>

#include<math、h>

#define MAX_DATE_SIZE 9

int Days[12]={31,28,31,30,31,30,31,31,30,30,31};

typedef struct Date

{

int Year;

int Month;

int Day;

}Date;

int main(int argc,char *argv)

{

int i,L;

int HLN1,HLN2;

int sDay,eDay;

Date sDate,eDate;

char sdate[MAX_DATE_SIZE],edate[MAX_DATE_SIZE];

while(scanf("%s",sdate)!=EOF)

{

 sDay=0;

 eDay=0;

 //日期格式转化

 sDate、Year=(sdate[0]-'0')*1000+(sdate[1]-'0')*100+(sdate[2]-'0')*10+(sdate[3]-'0');

 sDate、Month=(sdate[4]-'0')*10+(sdate[5]-'0');

 sDate、Day=(sdate[6]-'0')*10+(sdate[7]-'0');

 scanf("%s",edate);

 eDate、Year=(edate[0]-'0')*1000+(edate[1]-'0')*100+(edate[2]-'0')*10+(edate[3]-'0');

 eDate、Month=(edate[4]-'0')*10+(edate[5]-'0');

 eDate、Day=(edate[6]-'0')*10+(edate[7]-'0');

 HLN1=(int)(sDate、Year/4) (int)(sDate、Year/100)+(int)(sDate、Year/400);

 HLN2=(int)(eDate、Year/4) (int)(eDate、Year/100)+(int)(eDate、Year/400);

 for(i=0;i<sDate、Month-1;++i) sDay+=Days[i];

 for(i=0;i<eDate、Month-1;++i) eDay+=Days[i];

 sDay+=sDate、Day;

 eDay+=eDate、Day;

 L=(int)fabs((sDate、Year*365+HLN1+sDay) (eDate、Year*365+HLN2+eDay))+1;

 printf("%d\n",L);

}

return 1;

}

8、 题目描述://蔡勒公式

计算星期几公式

#include<iostream>

usingnamespacestd;

intmain(){

intyear,month,day;

while(cin>>year>>month>>day){

if(month<3){

year-=1;

month+=12;

}

charb[7][10]={"sunday","monday","tuesday","wednesday","thursday","friday","saturday"};

intc=int(year/100),y=year-100*c;

intw=int(c/4) 2*c+y+int(y/4)+(26*(month+1)/10)+day-1;

w=(w%7+7)%7;

cout<<b[w]<<endl;

We now use the Gregorian style of dating in Russia、 The leap years are years with number divisible by 4 but not divisible by 100, or divisible by 400、

For example, years 2004, 2180 and 2400 are leap、 Years 2004, 2181 and 2300 are not leap、

Your task is to write a program which will compute the day of week corresponding to a given date in the nearest past or in the future using today’s agreement about dating、

输入:

There is one single line contains the day number d, month name M and year number y(1000≤y≤3000)、 The month name is the corresponding English name starting from the capital letter、

输出:

Output a single line with the English name of the day of week corresponding to the date, starting from the capital letter、 All other letters must be in lower case、

样例输入:

9 October 2001

14 October 2001

样例输出:

Tuesday

Sunday

#include<iostream>

#include<cstring>

using namespace std;

int main()

{

char month[12][20]={"January","February","March","April","May","June","July","August","September","October","November","December"};//egg broken、、、

string week[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};

int m_day[12]={0,3,3,6,1,4,6,2,5,0,3,5};

int l_day[12]={0,3,4,0,2,5,0,3,6,1,4,6};

int year,day,m,ans;

char mon[20];

while(cin>>day>>mon>>year)

{

 int i;

 for(i=0;i<12;i++)

 {

     if(strcmp(month[i],mon)==0)

  m=i;

 }

 if((year%4==0&&year%100!=0)||(year%400==0))

     ans=(year+year/4+year/400-year/100-2+l_day[m]+day)%7;

 else

     ans=(year+year/4+year/400-year/100-1+m_day[m]+day)%7;

 cout<<week[ans]<<endl;

}

return 0;

}

9、 题目描述:

输入年、月、日,计算该天是本年的第几天。

输入:

包括三个整数年(1<=Y<=3000)、月(1<=M<=12)、日(1<=D<=31)。

输出:

输入可能有多组测试数据,对于每1组测试数据,

输出1个整数,代表Input中的年、月、日对应本年的第几天。

样例输入:

1990 9 20

2000 5 1

样例输出:

263

122

#include <iostream>

using namespace std;

bool fun(int year,int month)

{

 if((year%400==0||(year%4==0&&year%100!=0))&&month>2)return true;//是闰年且月份大于2月

 else return false;

}

int main()

{

 int y,m,d;

 while(cin>>y>>m>>d)

 {

  if(y<1||y>3000||m<1||m>12||d<1||d>31)return 1;

  int sum=0;

  switch(m)

  {

  case 12: sum+=30;

  case 11: sum+=31;

  case 10: sum+=30;

  case 9: sum+=31; 

  case 8: sum+=31; 

  case 7: sum+=30; 

  case 6: sum+=31; 

  case 5: sum+=30; 

  case 4: sum+=31; 

  case 3: sum+=28; 

  case 2: sum+=31; 

  default:break;

  }

  sum+=d;

  if(fun(y,m))sum++;

  cout<<sum<<endl;

 }

 return 0;

}

10、 题目描述:

给出年分m和1年中的第n天,算出第n天是几月几号。

输入:

输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。

输出:

可能有多组测试数据,对于每组数据,

按 yyyy-mm-dd的格式将输入中对应的日期打印出来。

样例输入:

2000 3

2000 31

2000 40

2000 60

2000 61

2001 60

样例输出:

2000-01-03

2000-01-31

2000-02-09

2000-02-29

2000-03-01

2001-03-01

#include <stdio、h>

#include <stdlib、h>

#include <string、h>

void showFormatdate(int, int);

int main()

{

 int year, dates;

 while(scanf("%d %d", &year, &dates) != EOF)

 {

  showFormatdate(year, dates);

 }

}

void showFormatdate(int year, int dates)

{

 int sum, i, m, d;

 int month[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

 if((year % 100 == 0) && (year % 400 == 0) || (year % 4 == 0) && (year % 100 != 0))

 {

  //润年

  month[1] = 29;

 }

  

 for(i = 0, sum = 0; i < 12; i ++)

 {

  if(sum < dates)

  {

   sum += month[i];

  }else

  {

   break;

  }

 }

 //获取月份

 m = i;

 //获取当月的天数

 d = month[i - 1] - (sum - dates);

 //格式化输出

 printf("%04d-%02d-%02d\n",year, m, d);

}

11、 题目描述:

读入N名学生的成绩,将获得某1给定分数的学生人数输出。

输入:

测试输入包含若干测试用例,每个测试用例的格式为

第1行:N

第2行:N名学生的成绩,相邻两数字用1个空格间隔。

第3行:给定分数

当读到N=0时输入结束。其中N不超过1000,成绩分数为(包含)0到100之间的1个整数。

输出:

对每个测试用例,将获得给定分数的学生人数输出。

样例输入:

3

80 60 90

60

2

85 66

0

5

60 75 90 55 75

75

0

样例输出:

1

0

2

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

double t[1005],a;

int N;

int main()

{

 int i;

 while(cin>>N && N)

 {

  int ans = 0;

  for(i = 0; i<N; i++)

   cin>>t[i];

  cin>>a;

  for(i = 0; i<N; i++)

  if(t[i] == a)ans++;

  cout<<ans<<endl;

 }

 return 0;

}

12、 题目描述:

输入1个ip地址串,判断是否合法。

输入:

输入的第1行包括1个整数n(1<=n<=500),代表下面会出现的IP地址的个数。

接下来的n行每行有1个IP地址,IP地址的形式为a、b、c、d,其中a、b、c、d都是整数。

输出:

可能有多组测试数据,对于每组数据,如果IP地址合法则输出"Yes!”,否则输出"No!”。

样例输入:

2

255、255、255、255

512、12、2、3

样例输出:

Yes!

No!

提示:

合法的IP地址为:

a、b、c、d都是0-255的整数。

#include <iostream>

using namespace std;

int main(){

int n;

int p1,p2,p3,p4;

while (cin>>n)

{

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

 {

 char c;

 cin>>p1>>c>>p2>>c>>p3>>c>>p4;

     if(p1>=0 && p2>=0 && p3>=0 && p4>=0 && p1<=255 && p2<=255 && p3<=255 && p4<=255){

     cout<<"Yes!"<<endl;

     }

     else{

     cout<<"No!"<<endl;

     }

 }

}

return 0;

}

13、 题目描述:

给你n个整数,请按从大到小的顺序输出其中前m大的数。

输入:

每组测试数据有两行,第1行有两个数n,m(0<n,m<1000000),第2行包含n个各不相同,且都处于区间[-500000,500000]的整数。

输出:

对每组测试数据按从大到小的顺序输出前m大的数。

样例输入:

5 3

3 -35 92 213 -644

样例输出:

213 92 3

#include <cstdio>

#include <algorithm>

#include <functional>

using namespace std;

#define left(i) ((i + 1) * 2 - 1)

#define right(i) (left(i) + 1)

#define parent(i) ((i + 1) / 2)

void heapify(int a[], int n, int index)

{

while (true) {

 int i = index;

 int l = left(i), r = right(i);

 if (l < n) {

     i = a[i] < a[l] ? i : l;

 }

 if (r < n) {

     i = a[i] < a[r] ? i : r;

 }

 if (i != index) {

     std::swap(a[i], a[index]);

     index = i;

 } else {

     break;

 }

}

}

void make_heap(int a[], int n)

{

for (int i = parent(n - 1); i >= 0; --i) {

 heapify(a, n, i);

}

}

int main()

{

int n, m;

while (scanf("%d %d", &n, &m) != EOF) {

 int *a = new int[m];

 for (int i = 0; i < m; ++i) {

     scanf("%d", &a[i]);

 }

 make_heap(a, m);

 int num;

 for (int i = m; i < n; ++i) {

     scanf("%d", &num);

     if (num > a[0]) {

  a[0] = num;

  heapify(a, m, 0);

     }

 }

 sort(a, a + m, greater<int>());

 printf("%d", a[0]);

 for (int i = 1; i < m; ++i) {

     printf(" %d", a[i]);

 }

 printf("\n");

}

return 0;

}

14、题目描述:

“臭味相投”——这是我们描述朋友时喜欢用的词汇。两个人是朋友通常意味着他们存在着许多共同的兴趣。然而作为1个宅男,你发现自己与他人相互了解的机会并不太多。幸运的是,你意外得到了1份北大图书馆的图书借阅记录,于是你挑灯熬夜地编程,想从中发现潜在的朋友。

首先你对借阅记录进行了1番整理,将N个读者依次编号为1,2,…,N,将M本书依次编号为1,2,…,M。同时,按照“臭味相投”的原则,和你喜欢读同1本书的人,就是你的潜在朋友。你现在的任务是从这份借阅记录中计算出每个人有几个潜在朋友。

输入:

每个案例第1行两个整数N,M,2 <= N ,M<= 200。接下来有N行,第i(i = 1,2,…,N)行每1行有1个数,表示读者i-1最喜欢的图书的编号P(1<=P<=M)

输出:

每个案例包括N行,每行1个数,第i行的数表示读者i有几个潜在朋友。如果i和任何人都没有共同喜欢的书,则输出“BeiJu”(即悲剧,^ ^)

样例输入:

4  5

2

3

2

1

样例输出:

1

BeiJu

1

BeiJu

#include <iostream>

#include <set>

using namespace std;

int main(void)

{

 multiset<int> record;

 int N, M;

 int ss[200];

 while (cin >> N >> M)

 {

  for (int i=0; i < N; i++)

  {

   cin >> ss[i];

   record、insert(ss[i]);

  }

  

  for (int i=0; i < N; i++)

  {

   if (record、count(ss[i]) == 1)

   {

    cout << "BeiJu" << endl;

   }

   else

   {

    cout << record、count(ss[i]) 1 << endl;

   }

  }

  

  record、clear();

 }

 return 0;

}

15、 题目描述:

将M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同1种分法。

输入:

第1行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。

输出:

对输入的每组数据M和N,用1行输出相应的K。

样例输入:

1

7 3

样例输出:

8

#include <iostream>

using namespace std;

int f(int m,int n)

{

 if(n==1)

  return 1;

 else if(m==1||m==0)

  return 1;

 else if(m<0)

  return 0;

 else

  return f(m,n-1)+f(m-n,n);

}

int main()

{

 int m,n;

 int t;

 cin>>t;

 while(t--)

 {

  cin>>m>>n;

  cout<<f(m,n)<<endl;

 }

 return 0;

}

16、 有1个长度为整数L(1<=L<=10000)的马路,可以想象成数轴上长度为L的1个线段,起点是坐标原点,在每个整数坐标点有1棵树,即在0,1,2,、、、,L共L+1个位置上有L+1棵树。

现在要移走1些树,移走的树的区间用1对数字表示,如 100 200表示移走从100到200之间(包括端点)所有的树。

可能有M(1<=M<=100)个区间,区间之间可能有重叠。现在要求移走所有区间的树之后剩下的树的个数。

输入:

两个整数L(1<=L<=10000)和M(1<=M<=100)。

接下来有M组整数,每组有1对数字。

输出:

可能有多组输入数据,对于每组输入数据,输出1个数,表示移走所有区间的树之后剩下的树的个数。

样例输入:

500 3

100 200

150 300

470 471

#include <stdio、h>

#define MAXLEN 10001

int main(){

#ifdef ONLINE_JUDGE

#else

freopen("E:\\in、txt", "r", stdin);

#endif

 int L[MAXLEN];

 int l, m;

 while (scanf ("%d%d", &l, &m) != EOF){

  for (int i = 0; i <= l; i++){ //注意i的范围是i<=l not i<l

   L[i] = 1;

  }// 初始化,种l+1棵树

  

  int a, b;

  for (int i = 1; i <= m; i++){

   scanf("%d%d", &a, &b);

   for(int j = a; j <= b; j++){

    L[j] = 0;

   }// 移走

  }// m组

  

  int left=0;

  for (int i = 0; i <= l; i++){

   if (L[i] == 1)

    left++;

  }

  printf("%d\n", left);

 }// while:zu

 return 0;

}

17、 题目描述:

输入1个高度h,输出1个高为h,上底边为h的梯形。

输入:

1个整数h(1<=h<=1000)。

输出:

h所对应的梯形。

样例输入:

4

样例输出:

  ****

******

********

**********

#include<stdio、h>

#include<string、h>

int main(void)

{

 int h;

 while(scanf("%d",&h) != EOF)

 {

  int i,j;

  for(i = 1; i <= h; ++i)

  {

   for(j = 1; j <= 2 * h - 2 * i; ++j)

    printf(" ");

   for(j = 2 * h - 2 * i + 1; j <= 3 * h - 2; ++j)

    printf("*");

   printf("\n");

  }

 }

 return 0;

}

18、 题目描述:

将1个个大小差1圈的筐叠上去,使得从上往下看时,边筐花色交错。这个工作现在要让计算机来完成,得看你的了。

输入:

输入是1个个的三元组,分别是,外筐尺寸n(n为满足0<n<80的奇整数),中心花色字符,外筐花色字符,后二者都为ASCII可见字符;

输出:

输出叠在1起的筐图案,中心花色与外筐花色字符从内层起交错相叠,多筐相叠时,最外筐的角总是被打磨掉。叠筐与叠筐之间应有1行间隔。

样例输入:

11 B A

5 @ W

样例输出:

AAAAAAAAA

ABBBBBBBBBA

ABAAAAAAABA

ABABBBBBABA

ABABAAABABA

ABABABABABA

ABABAAABABA

ABABBBBBABA

ABAAAAAAABA

ABBBBBBBBBA

AAAAAAAAA

#include <stdio、h>

#include <malloc、h>

int main(){

int n;

char pic[80][80];

char first, second;

while(scanf("%d %c %c", &n, &first, &second) != EOF){

 int min, max, floor = 0;

 for(min = max = n / 2 ;min>=0&&max<n; min--, max++, floor ++)

 {

     char c = floor%2==0? first:second;

     for(int j = min; j<=max; j++){

  pic[min][j] =c;

  pic[max][j] =c;

  pic[j][max] =c;

  pic[j][min] =c;

     }

 }

 if(n > 1)    pic[0][0] = pic[0][n-1] = pic[n-1][0] =pic[n-1][n -1] = ' ';

 //print pattern

 for(int i = 0; i< n; i ++){

     for(int j = 0 ; j < n; j++){

  printf("%c", pic[i][j]);

     }

     printf("\n");

 }

 printf("\n");

}

}

19、 题目描述:

Harmony is indispensible in our daily life and no one can live without it----may be Facer is the only exception、 One day it is rumored that repeat painting will create harmony and then hundreds of people started their endless drawing、 Their paintings were based on a small template and a simple method of duplicating、 Though Facer can easily imagine the style of the whole picture, but he cannot find the essential harmony、 Now you need to help Facer by showing the picture on computer、

You will be given a template containing only one kind of character and spaces, and the template shows how the endless picture is created----use the characters as basic elements and put them in the right position to form a bigger template, and then repeat and repeat doing that、 Here is an example、

# #

#  <-template

# #

So the Level 1 picture will be

# #

#

# #

Level 2 picture will be

# # # #

#  #

# # # #

 # #

  #

 # #

# #    # #

# #

# #    # #

输入:

The input contains multiple test cases、

The first line of each case is an integer N, representing the size of the template is N*N (N could only be 3, 4 or 5)、

Next N lines describe the template、

The following line contains an integer Q, which is the Scale Level of the picture、

Input is ended with a case of N=0、

It is guaranteed that the size of one picture will not exceed 3000*3000、

输出:

For each test case, just print the Level Q picture by using the given template、

样例输入:

3

# #

#

# #

1

3

# #

#

# #

3

4

OO

O  O

O  O

OO

2

0

样例输出:

# #

#

# #

# #   # #  # #   # #

# #    # #

# #   # #  # #   # #

# #    # #

#   #

# #    # #

# #   # #  # #   # #

# #    # #

# #   # #  # #   # #

  # #   # # 

   # # 

  # #   # # 

     # # 

  #  

     # # 

  # #   # # 

   # # 

  # #   # # 

# #   # #  # #   # #

# #    # #

# #   # #  # #   # #

# #    # #

#   #

# #    # #

# #   # #  # #   # #

# #    # #

# #   # #  # #   # #

 OO  OO 

O  OO  O

O  OO  O

 OO  OO 

OO   OO

O  O O  O

O  O O  O

OO   OO

OO   OO

O  O O  O

O  O O  O

OO   OO

 OO  OO 

O  OO  O

O  OO  O

 OO  OO

#include <iostream>

#include <stdio、h>

#include <algorithm>

#include <string>

#include <string、h>

#include <functional>

#include <vector>

#include <cmath>

using namespace std;

void shape_str2char(string src[] , char* dest[], int x, int y, int n){

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

  for(int j=0; j<n; j++)

   dest[x+i][y+j]=src[i]、at(j);

}

void shape_char2char(char* src[], char* dest[], int x, int y, int n){

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

  for(int j=0; j<n; j++)

   dest[x+i][y+j]=src[i][j];

}

void shape_recur(int depth, char* templ[], char* dest[], int x, int y, int size){

 if(depth==1)

  shape_char2char(templ, dest, x, y, size);

 else{

  for(int i=0; i<size; i++)

   for(int j=0; j<size; j++)

    if(templ[i][j]!=' ')

     shape_recur(depth-1, templ, dest, x+i*pow(double(size), depth-1), y+j*pow(double(size), depth-1), size);

 }

}

int main(){

 int size_templ;

 while(scanf("%d", &size_templ) && size_templ!=0){

  //sp1

  while(getchar() != '\n')

   continue;

  char* str[6];

  for(int i=0; i<6; i++) str[i] = new char[6];

  for(int i=0; i<size_templ; i++) gets(str[i]);

  //sp2

  char* templ[6];

  for(int i=0; i<6; i++) templ[i] = new char[6];

  shape_char2char(str, templ, 0, 0, size_templ);

  //sp3

  int num;

  scanf("%d", &num);

  int size_pic = pow((double)size_templ, num);

  char *Pic[3001];

  for(int i=0; i<3001; i++) Pic[i] = new char[3001];

  for(int i=0; i<3001; i++)

   for(int j=0; j<3001; j++)

    Pic[i][j]=' ';

  shape_recur(num, templ, Pic, 0, 0, size_templ);

  //sp4

  for(int i=0; i<size_pic; i++){

   for(int j=0; j<size_pic; j++)

    printf("%c", Pic[i][j]);

   printf("\n");

  }

  for(int i=0; i<6; i++) delete(str[i]);

  for(int i=0; i<3001; i++) delete(Pic[i]);

 }

}

20、 题目描述:

输入1个数n,然后输入n个数值各不相同,再输入1个值x,输出这个值在这个数组中的下标(从0开始,若不在数组中则输出-1)。

输入:

测试数据有多组,输入n(1<=n<=200),接着输入n个数,然后输入x。

输出:

对于每组输入,请输出结果。

样例输入:

2

1 3

0

样例输出:

-1

#include <stdio、h>

int main()

{

 int n;

 while (scanf("%d",&n)!=EOF)

 {

  int x,a[200],fla=0;

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

  {

   scanf("%d",&a[i]);

  }

  scanf("%d",&x);

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

  {

   if (a[i]==x)

   {

    printf("%d\n",i);

    fla=1;

    break;

   } 

  }

  if (fla==0)

  {

   printf("-1\n");

  }

 }

 return 0;

}

21、 题目描述:

输入N个学生的信息,然后进行查询。

输入:

输入的第1行为N,即学生的个数(N<=1000)

接下来的N行包括N个学生的信息,信息格式如下:

01 李江 男 21

02 刘唐 男 23

03 张军 男 19

04 王娜 女 19

然后输入1个M(M<=10000),接下来会有M行,代表M次查询,每行输入1个学号,格式如下:

02

03

01

04

输出:

输出M行,每行包括1个对应于查询的学生的信息。

如果没有对应的学生信息,则输出“No Answer!”

样例输入:

4

01 李江 男 21

02 刘唐 男 23

03 张军 男 19

04 王娜 女 19

5

02

03

01

04

03

样例输出:

02 刘唐 男 23

03 张军 男 19

01 李江 男 21

04 王娜 女 19

03 张军 男 19

#include<iostream>

#include<fstream>

#include<algorithm>

#include<string>

#include<map>

using namespace std;

int main()

{

 string id,info,str;

 int i,index,n,M;

 map<string,string> m;

map<string,string>::iterator iter;

// fstream cin("1069、txt");

 while (cin>>n)

 {

  cin、ignore();

  m、clear();

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

  {

   getline(cin,str);

   index=str、find(" ");

   id=str、substr(0,index);

   info=str、substr(index+1);

   m、insert(pair<string,string>(id,info));

  }

  cin>>M;

  for (i=0;i<M;i++)

  {

   cin>>id;

   iter=m、find(id);

   if (iter!=m、end())

   {

    cout<<iter->first<<" "<<iter->second<<endl;

   }

   else

   {

    cout<<"No Answer!"<<endl;

   }

  }

 }

 return 0;

}

22、 题目描述:

在1个整数数组上,对于下标为i的整数,如果它大于所有它相邻的整数,

或者小于所有它相邻的整数,则称为该整数为1个极值点,极值点的下标就是i。

输入:

每个案例的输入如下:

有2×n+1行输入:第1行是要处理的数组的个数n;

对其余2×n行,第1行是此数组的元素个数k(4<k<80),第2行是k个整数,每两个整数之间用空格分隔。

输出:

每个案例输出为n行:每行对应于相应数组的所有极值点下标值,下标值之间用空格分隔。

样例输入:

3

10

10 12 12 11 11 12 23 24 12 12

15

12 12 122 112 222 211 222 221 76 36 31 234 256 76 76

15

12 14 122 112 222 222 222 221 76 36 31 234 256 76 73

样例输出:

0 7

2 3 4 5 6 10 12

0 2 3 10 12 14

#include<iostream>

#include<vector>

using namespace std;

int main()

{

 int n;

 while(cin >> n)

 {

  while(n--)

  {

   int k,i;

   cin >> k;

   vector<int> vv(k);

   for(i = 0;i < k;i++) cin >> vv[i];

   vector<int> out;

   out、reserve(k);

   if(vv[0] < vv[1]||vv[0] > vv[1]) out、push_back(0);

   for(i = 1;i <= k-2;i++)

   {

    if(vv[i] > vv[i-1]&&vv[i] > vv[i+1]) out、push_back(i);

    if(vv[i] < vv[i-1]&&vv[i] < vv[i+1]) out、push_back(i);

   }

   if(vv[k-1] < vv[k-2]||vv[k-1] > vv[k-2]) out、push_back(k-1);

   for(i = 0;i < out、size() - 1;i++) cout << out[i] << " ";

   cout << out[i] << endl;

  }

 }

 return 0;

}

23、 题目描述:

输入数组长度 n

输入数组  a[1、、、n]

输入查找个数m

输入查找数字b[1、、、m]

输出 YES or NO  查找有则YES 否则NO 。

输入:

输入有多组数据。

每组输入n,然后输入n个整数,再输入m,然后再输入m个整数(1<=m<=n<=100)。

输出:

如果在n个数组中输出YES否则输出NO。

样例输入:

5

1 5 2 4 3

3

2 5 6

样例输出:

YES

YES

NO

#include<iostream>

#include<vector>

#include<algorithm>

using namespace std;

int main()

{

 int temp,i,n,m;

 vector<int> v;

 while (cin>>n)

 {

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

  {

   cin>>temp;

   v、push_back(temp);

  }

  cin>>m;

  for (i=0;i<m;i++)

  {

   cin>>temp;

   vector<int>::iterator index=find(v、begin(),v、end(),temp);//刚学的iterator迭代器用法,并使用系统提供的find方法

   if (index==v、end())

   {

    cout<<"NO"<<endl;

   }

   else

   {

    cout<<"YES"<<endl;

   }

  } 

 }

 return 0;

}

23、 题目描述:

FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean、

The warehouse has N rooms、 The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food、 FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food、 Here a is a real number、 Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain、

输入:

The input consists of multiple test cases、 Each test case begins with a line containing two non-negative integers M and N、 Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively、 The last test case is followed by two -1's、 All integers are not greater than 1000、

输出:

For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain、

样例输入:

5 3

7 2

4 3

5 2

20 3

25 18

24 15

15 10

-1 -1

样例输出:

13、333

31、500

#include <cstdio>

#include <vector>

#include <algorithm>

using namespace std;

struct Room {

int beans;

int cost;

double ratio;

};

struct Cmp {

bool operator()(const Room &a, const Room &b) {

 return a、ratio > b、ratio;

}

};

int main()

{

Cmp cmp;

int food, n;

while (scanf("%d %d", &food, &n) != EOF && food != -1) {

 vector<Room> rooms;

 for (int i = 0; i < n; ++i) {

     Room room;

     scanf("%d %d", &room、beans, &room、cost);

     room、ratio = room、beans / (double)room、cost;

     rooms、push_back(room);

 }

 sort(rooms、begin(), rooms、end(), cmp);

 int index = 0;

 double beans = 0、0;

 while (food && index < n) {

     Room &room = rooms[index];

     if (food >= room、cost) {

  food -= room、cost;

  beans += room、beans;

  ++index;

     } else {

  double ratio = food / (double)room、cost;

  beans += room、beans * ratio;

  break;

     }

 }

 printf("%、3f\n", beans);

}

return 0;

}

24、 题目描述:

“今年暑假不AC?”“是的。”“那你干什么呢?”“看世界杯呀,笨蛋!”“@#$%^&*%、、、”确实如此,世界杯来了,球迷的节日也来了,估计很多ACMer也会抛开电脑,奔向电视作为球迷,1定想看尽量多的完整的比赛,当然,作为新时代的好青年,你1定还会看1些其它的节目,比如新闻联播(永远不要忘记关心国家大事)、非常6+7、超级女生,以及王小丫的《开心辞典》等等,假设你已经知道了所有你喜欢看的电视节目的转播时间表,你会合理安排吗?(目标是能看尽量多的完整节目)

输入:

输入数据包含多个测试实例,每个测试实例的第1行只有1个整数n(n<=100),表示你喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1<=i<=n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用1个正整数表示。n=0表示输入结束,不做处理。

输出:

对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占1行。

样例输入:

12

1 3

3 4

0 7

3 8

15 19

15 20

10 15

8 18

6 12

5 10

4 14

2 9

0

样例输出:

5

#include <cstdio>

#include <algorithm>

using namespace std;

struct ss{

int st,ed;

}node[102];

bool cmp(ss x,ss y){

if(x、ed!=y、ed)  return x、ed<y、ed;

else    return x、st>y、st;

}

int main(){

int n;

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

 if(n==0)    return 0;

 else{

     for(int i=0;i<n;++i){

  scanf("%d %d",&node[i]、st,&node[i]、ed);

     }

     sort(node,node+n,cmp);

     int num=1,k=0;

     for(int j=0;j<n;j++){

  if(node[j]、st>=node[k]、ed){

      num++;

      k=j;

  }

     }

     printf("%d\n",num);

 }

}

}

24、 题目描述:

通过悬崖的yifenfei,又面临着幽谷的考验——

幽谷周围瘴气弥漫,静的可怕,隐约可见地上堆满了骷髅。由于此处长年不见天日,导致空气中布满了毒素,1旦吸入体内,便会全身溃烂而死。

幸好yifenfei早有防备,提前备好了解药材料(各种浓度的万能药水)。现在只需按照配置成不同比例的浓度。

现已知yifenfei随身携带有n种浓度的万能药水,体积V都相同,浓度则分别为Pi%。并且知道,针对当时幽谷的瘴气情况,只需选择部分或者全部的万能药水,然后配置出浓度不大于 W%的药水即可解毒。

现在的问题是:如何配置此药,能得到最大体积的当前可用的解药呢?

特别说明:由于幽谷内设备的限制,只允许将1种已有的药全部混入另1种之中(即:不能出现对1种药只取它的1部分这样的操作)。

输入:

输入数据的第1行是1个整数C,表示测试数据的组数;

每组测试数据包含2行,首先1行给出三个正整数n,V,W(1<=n,V,W<=100);

接着1行是n个整数,表示n种药水的浓度Pi%(1<=Pi<=100)。

输出:

对于每组测试数据,请输出1个整数和1个浮点数;

其中整数表示解药的最大体积,浮点数表示解药的浓度(四舍五入保留2位小数);

如果不能配出满足要求的的解药,则请输出0 0、00。

样例输入:

3

1 100 10

100

2 100 24

20 30

3 100 24

20 20 30

样例输出:

0 0、00

100 0、20

300 0、23

#include <cstdio>

#include <cstring>

#include <algorithm>

#include <iostream>

#include <cmath>

using namespace std;

int main()

{

 int c;

 cin >> c;

 for(;c>0;c--)

 {

  int n,v,w;

  cin >> n >> v >> w;

  int buf[100];

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

   cin >> buf[i];

  sort(buf,buf+n);//解药按浓度排序

  int currW = 0;

  int currV = 0;

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

  {

   if(buf[i] <= w)

   {

    currW = (buf[i]*v + currW);

    currV += v;

   }

   else

    if((buf[i]*v + currW) <= w*(currV+v))

    {

     currW = currW + buf[i]*v;

     currV += v;

    }

    else

     break;

  }

  cout << currV << " 0、";

  currW = floor((double)currW/currV + 0、5);

  if(currV == 0)currW = 0;

  printf("%02d",currW);

  cout << endl;

 }

 //system("pause");

}

25、 题目描述:

Long time ago , Kitty lived in a small village、 The air was fresh and the scenery was very beautiful、 The only thing that troubled her is the typhoon、

When the typhoon came, everything is terrible、 It kept blowing and raining for a long time、 And what made the situation worse was that all of Kitty's walls were made of wood、

One day, Kitty found that there was a crack in the wall、 The shape of the crack is

a rectangle with the size of 1×L (in inch)、 Luckly Kitty got N blocks and a saw(锯子) from her neighbors、

The shape of the blocks were rectangle too, and the width of all blocks were 1 inch、 So, with the help of saw, Kitty could cut down some of the blocks(of course she could use it directly without cutting) and put them in the crack, and the wall may be repaired perfectly, without any gap、

Now, Kitty knew the size of each blocks, and wanted to use as fewer as possible of the blocks to repair the wall, could you help her ?

输入:

The problem contains many test cases, please process to the end of file( EOF )、

Each test case contains two lines、

In the first line, there are two integers L(0<L<1000000000) and N(0<=N<600) which

mentioned above、

In the second line, there are N positive integers、 The ith integer Ai(0<Ai<1000000000 ) means that the ith block has the size of 1×Ai (in inch)、

输出:

For each test case , print an integer which represents the minimal number of blocks are needed、

If Kitty could not repair the wall, just print "impossible" instead、

样例输入:

5 3

3 2 1

5 2

2 1

样例输出:

2

Impossible

#include<stdio、h>

#include<algorithm>

using namespace std;

bool cmp(int a,int b)

{

return a>b;

}

int main()

{

int i,N;

long long L,A[601];

while(scanf("%lld%lld",&L,&N)!=EOF)

{

for(i=0;i<N;i++)

{

  scanf("%lld",&A[i]);

}

sort(A,A+N,cmp);

bool flag=true;

int sum=0,k=0;

for(i=0;i<N;i++)

{

  if((sum+A[i])<L)

  {

 k++;

 sum+=A[i];

  }

  else

  {

 k++;

 flag=false;

 break;

  }

}

if(flag)

{

  printf("impossible\n");

}

else

{

  printf("%d\n",k);

}

}

return 0;

}

26、 题目描述:

With highways available, driving a car from Hangzhou to any other city is easy、 But since the tank capacity of a car is limited, we have to find gas stations on the way from time to time、 Different gas station may give different price、 You are asked to carefully design the cheapest route to go、

输入:

For each case, the first line contains 4 positive numbers: Cmax (<= 100), the maximum capacity of the tank; D (<=30000), the distance between Hangzhou and the destination city; Davg (<=20), the average distance per unit gas that the car can run; and N (<= 500), the total number of gas stations、 Then N lines follow, each contains a pair of non-negative numbers: Pi, the unit gas price, and Di (<=D), the distance between this station and Hangzhou, for i=1,、、、N、 All the numbers in a line are separated by a space、

输出:

For each test case, print the cheapest price in a line, accurate up to 2 decimal places、 It is assumed that the tank is empty at the beginning、 If it is impossible to reach the destination, print "The maximum travel distance = X" where X is the maximum possible distance the car can run, accurate up to 2 decimal places、

样例输入:

50 1300 12 8

6、00 1250

7、00 600

7、00 150

7、10 0

7、20 200

7、50 400

7、30 1000

6、85 300

50 1300 12 2

7、10 0

7、00 600

样例输出:

749、17

The maximum travel distance = 1200、00

#include <stdio、h>

#include <stdlib、h>

#include <math、h>

#define MAXN 501

#define MAXC 30000000、0

typedef struct station{

float price;

int dist;

}Station;

int compare(const void * p, const void * q){

Station * p1 = (Station *)p;

Station * q1 = (Station *)q;

return p1->dist - q1->dist;

}

int main(void){

int Cmax, D, Davg, N;  //ÈÝÁ¿¡¢¾àÀ롢ÿµ¥Î»ÆøÐÐÊ»µÄ¾àÀë¡¢¼ÓÆøÕ¾×ÜÊý

int i;

Station sta[MAXN];

float sum, remind_gas, tmp;

int k, step;

while (scanf("%d %d %d %d", &Cmax, &D, &Davg, &N) != EOF){

 for (i=0; i<N; ++i){

     scanf("%f %d", &sta[i]、price, &sta[i]、dist);

 }

 sta[N]、dist = D;

 sta[N]、price = 1000000、0;

 qsort(sta, N, sizeof(Station), compare);  //°´Ó뺼ÖݾàÀë´óС¸ø¼ÓÆøÕ¾ÅÅÐò

 if (sta[0]、dist > 0){

     printf ("The maximum travel distance = 0、00\n");

     continue;

 }

 sum = 0;  //×Ü·ÑÓÃ

 step = Cmax*Davg;    //¼ÓÂúÓÍÐÐÊ»×î´ó¾àÀë

 remind_gas = 0;  //Ê£ÓàÓÍÁ¿

 for (i=0; i<N; ++i){

     k = i+1;

     if (i != 0)

  remind_gas -= ((float)(sta[i]、dist -sta[i-1]、dist))/Davg;

     for (; k<N && sta[k]、price>=sta[i]、price; ++k)

  continue;

     if (sta[k]、dist-sta[i]、dist > step){

  sum += (Cmax-remind_gas)*sta[i]、price;

  remind_gas = Cmax;

     }

     else{

  tmp = ((float)(sta[k]、dist-sta[i]、dist))/Davg - remind_gas;

  if (fabs(tmp)>1e-5 && tmp>0){

      sum += tmp*sta[i]、price;

      remind_gas = ((float)(sta[k]、dist-sta[i]、dist))/Davg;

  }

     }

     if (sta[i+1]、dist - sta[i]、dist > step){

  printf ("The maximum travel distance = %、2f\n", (float)(sta[i]、dist+step));

  break;

     }

 }

 if (i == N){

     printf ("%、2f\n", sum);

 }

}

return 0;

}

27、 题目描述:

在某个string(长度不超过100)中有左括号、右括号和大小写字母;规定(与常见的算数式子1样)任何1个左括号都从内到外与在它右边且距离最近的右括号匹配。写1个程序,找到无法匹配的左括号和右括号,输出原来string,并在下1行标出不能匹配的括号。不能匹配的左括号用"$"标注,不能匹配的右括号用"?"标注、

输入:

输入包括多组数据,每组数据1行,包含1个string,只包含左右括号和大小写字母,string长度不超过100。

注意:cin、getline(str,100)最多只能输入99个字符!

输出:

对每组输出数据,输出两行,第1行包含原始输入字符,第2行由"$","?"和空格组成,"$"和"?"表示与之对应的左括号和右括号不能匹配。

样例输入:

)(rttyy())sss)(

样例输出:

)(rttyy())sss)(

?     ?$

#include<stdio、h>

#include<string、h>

#include<stdlib、h>

#define MAX_LEN 110

int main(void)

{

 char *exp=(char*)malloc(sizeof(char)*MAX_LEN);

 int *res=(int*)malloc(sizeof(int)*MAX_LEN);

 while(gets(exp))

 {

  int cur=0,pt=0,len=strlen(exp);

  for(int i=0;i!=MAX_LEN;++i)

   res[i]=-1;

  for(;cur!=len;++cur)

  {

   if(exp[cur]!='('&&exp[cur]!=')')

    res[cur]=0;

   if(exp[cur]==')')

   {

    for(pt=cur-1;pt>=0;--pt)

    {

     if(exp[pt]=='('&&res[pt])

     {

      res[pt]=0;

      res[cur]=0;

      break;

     }

    }

   }

  }

  puts(exp);

  for(int i=0;i!=len;++i)

  {

   if(exp[i]=='('&&res[i]==-1)

    res[i]=1;

   else if(exp[i]==')'&&res[i]==-1)

    res[i]=2;

   switch(res[i])

   {

   case 0:

    putchar(' ');

    break;

   case 1:

    putchar('$');

    break;

   case 2:

    putchar('?');

    break;

   }

  }

  printf("\n");

 }

 return 0;

}

28、 题目描述:

读入1个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。

输入:

测试输入包含若干测试用例,每个测试用例占1行,每行不超过200个字符,整数和运算符之间用1个空格分隔。没有非法表达式。当1行中只有0时输入结束,相应的结果不要输出。

输出:

对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。

样例输入:

1 + 2

4 + 2 * 5 - 7 / 11

0

样例输出:

3、00

13、36

#include <stdio、h>

#include <string、h>

#include <stdlib、h>

#define size 500

int isfu(char a){

 return (a=='*' || '-'==a || '+'==a || '/'==a);

}

int isdig(char a){

 return a>='0' && a <= '9';

}

int mygets(char *s, int *len)

{

 char ch;

 (*len) = 0; 

 while ('\n' != (ch=getchar()))/*输入处理*/

 {

  if (isfu(ch)||isdig(ch))

   s[(*len)++] = ch;

 } 

 s[*len] = 0;

 if ((*len) == 1 && s[0] == '0') return 0;

 return 1;

}

main()

{

 char str[size], fu[size];

 int i, len, nd, nf, total,now; 

 double dig[size];

 while (mygets(str,&len))

 {  

  if (len == 0) continue;

  nd = nf = now = 0;

  for (i = 0; i < len; )

  {

   if (isfu(str[i]))

   {

    

    fu[nf++] = str[i];

    if ('*' == str[i] || '/' == str[i])    

     now = 1;/*得到下1个数后马上计算*/

    i++;

   }

   else

   {

    total = 0;

    while (str[i] >= '0' && str[i] <= '9')

    {

      total *= 10;

      total += (str[i] - '0') ;

      i++;

    }

    dig[nd++] = (double)total;

    if (now)

    {/*立马算*/

     nf--, nd--;

     if ('*' == fu[nf])

      dig[nd-1] = dig[nd-1] * dig[nd];

     else if ('/' == fu[nf])    

      dig[nd-1] = dig[nd-1] / dig[nd];

     

     now = 0;

    }

   }

  }

  i = 0;

  while (i<nd-1)/*只剩加减法*/

  {

   if ('-' == fu[i]) dig[i+1] = dig[i] - dig[i+1];

   else if ('+' == fu[i]) dig[i+1] +=  dig[i];   

   i++;

  }

  printf("%、2lf\n",dig[nd-1]);

 }

}

29、 题目描述:

堆栈是1种基本的数据结构。堆栈具有两种基本操作方式,push 和 pop。Push1个值会将其压入栈顶,而 pop 则会将栈顶的值弹出。现在我们就来验证1下堆栈的使用。

输入:

 对于每组测试数据,第1行是1个正整数 n,0<n<=10000(n=0 结束)。而后的 n 行,每行的第1个字符可能是'P’或者'O’或者'A’;如果是'P’,后面还会跟着1个整数,表示将这个数据压入堆栈;如果是'O’,表示将栈顶的值 pop 出来,如果堆栈中没有元素时,忽略本次操作;如果是'A’,表示询问当前栈顶的值,如果当时栈为空,则输出'E'。堆栈开始为空。

输出:

对于每组测试数据,根据其中的命令字符来处理堆栈;并对所有的'A’操作,输出当时栈顶的值,每个占据1行,如果当时栈为空,则输出'E’。当每组测试数据完成后,输出1个空行。

样例输入:

3

A

P 5

A

4

P 3

P 6

O

A

0

样例输出:

E

5

3

#include<iostream>

#include<fstream>

#include<vector>

#include<stack>

using namespace std;

int main()

{

 int i,n,temp;

 char ch;

 vector<int> v;

 stack<int> s;

// fstream cin("1108、txt");

 while (cin>>n,n)

 {

  v、clear();

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

  {

   cin>>ch;

   switch(ch)

   {

   case 'A':

    if (v、empty())

    {

     cout<<"E"<<endl;

    }

    else

    {

     cout<<v、back()<<endl;

    }

    break;

   case 'P':

    {

     cin>>temp;

     v、push_back(temp);

    }

    break;

   case 'O':

    {

     if (!v、empty())

     {

      v、pop_back();

     }

    }

    break;

   }

  }

  cout<<endl;

 }

 return 0;

}

30、 题目描述:

对于1个不存在括号的表达式进行计算

输入:

存在多种数据,每组数据1行,表达式不存在空格

输出:

输出结果

样例输入:

6/2+3+3*4

样例输出:

18

#include <iostream>

#include <stack>

using namespace std;

string str;

int pos;

double getNum(){

double v = 0;

for(;pos<str、length();pos++){

 if(str[pos]>'9'||str[pos]<'0'){

     break;

 }

 v *= 10;

 v += str[pos] - '0';

}

return 1、0*v;

}

int main(int argc,char* argv[]){

double a,b;

double v;

while(cin>>str){

 stack<double> s;

 pos = 0;

 s、push(getNum());

 while(pos<str、length()){

     if(str[pos]=='*'){

  pos++;

  a = s、top();

  s、pop();

  b = getNum();

  s、push(a*b);

     }

     if(str[pos]=='/'){

  pos++;

  a = s、top();

  s、pop();

  b = getNum();

  s、push(a/b);

     }

     if(str[pos]=='+'){

  pos++;

  s、push(getNum());

     }

     if(str[pos]=='-'){

  pos++;

  s、push(-1、0*getNum());

     }

 }

 v = 0;

 while(!s、empty()){

     v += s、top();

     s、pop();

 }

 cout<<v<<endl;

}

return 0;

}

31、 题目描述:

哈夫曼树,第1行输入1个数n,表示叶结点的个数。需要用这些叶结点生成哈夫曼树,根据哈夫曼树的概念,这些结点有权值,即weight,题目需要输出所有结点的值与权值的乘积之和。

输入:

输入有多组数据。

每组第1行输入1个数n,接着输入n个叶节点(叶节点权值不超过100,2<=n<=1000)。

输出:

输出权值。

样例输入:

5

1 2 2 5 9

样例输出:

37

#include <iostream>

#include <algorithm>

using namespace std;

int main()

{

int n;

while(cin>>n){

    int sum=0;

    int a[n];

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

    cin>>a[i];

    for(int i=1;i<n;i++)

    {

     sort(a+i-1,a+n);

     sum=a[i]+a[i-1]+sum;

     a[i]=a[i]+a[i-1];

     }

    cout<<sum<<endl; 

     }

return 0;

}

32、 题目描述:

在1个果园里,小明已经将所有的水果打了下来,并按水果的不同种类分成了若干堆,小明决定将所有的水果合成1堆。每1次合并,小明可以将两堆水果合并到1起,消耗的体力等于两堆水果的重量之和。当然经过 n‐1 次合并之后,就变成1堆了。小明在合并水果时总共消耗的体力等于每次合并所耗体力之和。

假定每个水果重量都为 1,并且已知水果的种类数和每种水果的数目,你的任务是设计出合并的次序方案,使小明耗费的体力最少,并输出这个最小的体力耗费值。示例有 3 种水果,数目依次为 1,2,9。可以先将 1,2 堆合并,新堆数目为3,耗费体力为 3。然后将新堆与原先的第三堆合并得到新的堆,耗费体力为 12。所以小明总共耗费体力=3+12=15,可以证明 15 为最小的体力耗费值。

输入:

每组数据输入包括两行,第1行是1个整数 n(1<=n<=10000),表示水果的种类数,如果 n 等于 0 表示输入结束,且不用处理。第2行包含 n 个整数,用空格分隔,第 i 个整数(1<=ai<=1000)是第 i 种水果的数目。

输出:

对于每组输入,输出1个整数并换行,这个值也就是最小的体力耗费值。输入数据保证这个值小于 2^31。

样例输入:

3

9 1 2

0

样例输出:

15

#include<iostream>

using namespace std;

int main(int argc,char* argv[])

{

 int n;

 int a[10000];

 int temp;

 int i,j;

 int t,k;

 int sum;

 while(cin>>n&&n!=0)

 {

  sum=0;

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

  {

   cin>>a[i];

  }

  t=n-1;

  while(t>0)

  {

   k=0;

   for(i=0;i<=t;i++)

    if(a[k]>a[i])

     k=i;

     temp=a[t];

   a[t]=a[k];

   a[k]=temp;  //a[t]为第1个最小值

  

   k=0;

   for(i=0;i<=t-1;i++)

    if(a[k]>a[i])

     k=i;

     temp=a[t-1];

   a[t-1]=a[k];

   a[k]=temp;  //a[t-1]为第2个最小值

   a[t-1]+=a[t];

   t--;

   sum+=a[t];

  }

  cout<<sum<<endl;

 }

 return 0;

}

33、 题目描述:

二叉树的前序、中序、后序遍历的定义:

前序遍历:对任1子树,先访问跟,然后遍历其左子树,最后遍历其右子树;

中序遍历:对任1子树,先遍历其左子树,然后访问根,最后遍历其右子树;

后序遍历:对任1子树,先遍历其左子树,然后遍历其右子树,最后访问根。

给定1棵二叉树的前序遍历和中序遍历,求其后序遍历(提示:给定前序遍历与中序遍历能够唯1确定后序遍历)。

输入:

两个string,其长度n均小于等于26。

第1行为前序遍历,第2行为中序遍历。

二叉树中的结点名称以大写字母表示:A,B,C、、、、最多26个结点。

输出:

输入样例可能有多组,对于每组测试样例,

输出1行,为后序遍历的string。

样例输入:

ABC

BAC

FDXEAG

XDEFAG

样例输出:

BCA

XEDGAF

#include <stdio、h>

#include <string、h>

#include <stdlib、h>

char s1[101],s2[101];

int a[101];

int k;

void fen(char *s2,int l,int h);

main()

{

  int i,j;

  while( scanf("%s %s",s1,s2) != EOF){

  k = -1;

  for(i = 0;i < strlen(s1);i++){

     for(j = 0;j < strlen(s2);j++){

    if(s1[i] == s2[j]) a[i] = j;

    }

     }

  

  fen(s2,0,strlen(s2) - 1);

  

  printf("\n");

  }

}

void fen(char *s2,int l,int h){

 int n;

 if(h < l) return ;

 if(h - l > 0) k++;

 n = a[k];

 if(l == h) {

   printf("%c",s2[h]);

   k++;

   return ;

   }

 fen(s2,l,n-1);

 fen(s2,n+1,h); 

 printf("%c",s2[n]);

 }

34、 题目描述:

如上所示,由正整数1,2,3……组成了1颗特殊二叉树。我们已知这个二叉树的最后1个结点是n。现在的问题是,结点m所在的子树中1共包括多少个结点。

比如,n = 12,m = 3那么上图中的结点13,14,15以及后面的结点都是不存在的,结点m所在子树中包括的结点有3,6,7,12,因此结点m的所在子树中共有4个结点。

输入:

输入数据包括多行,每行给出1组测试数据,包括两个整数m,n (1 <= m <= n <= 1000000000)。最后1组测试数据中包括两个0,表示输入的结束,这组数据不用处理。

输出:

对于每1组测试数据,输出1行,该行包含1个整数,给出结点m所在子树中包括的结点的数目。

样例输入:

3 12

0 0

样例输出:

4

#include <math、h>

#include <stdio、h>

int main()

{

 unsigned long n,sum=0,d;

 while(scanf("%d",&d))

 {

  unsigned long i;

  scanf("%d",&n);

  if (d==0&&n==0) break;

  unsigned long ddeep;

  ddeep=(unsigned long)(log(d)/log(2)+1);

  unsigned long d1,d2;

  d1=(unsigned long)(log(n)/log(2)+1);

  if(d>n)

  {

   printf("0\n");break;

  }   

  else

  {

   unsigned long j,k;

   k=d;

   unsigned long count=0;

      for(i=ddeep; i<d1-1; i++)

   {

    count++;

    k=2*k+1;

    for(j=d*pow(2,count);j<=k;j++)

    {

     sum++;

    }     

   }   

   count++;

   k=2*k+1;

   for (j=d*pow(2,count);j<=k&&j<=n;j++)

   {

    sum++;

   }   

  }

  printf("%d\n",++sum);

  sum=0;

 }

 return 0;

}

35、 题目描述:

有1棵树,输出某1深度的所有节点,有则输出这些节点,无则输出EMPTY。该树是完全二叉树。

输入:

输入有多组数据。

每组输入1个n(1<=n<=1000),然后将树中的这n个节点依次输入,再输入1个d代表深度。

输出:

输出该树中第d层得所有节点,节点间用空格隔开,最后1个节点后没有空格。

样例输入:

4

1 2 3 4

2

样例输出:

2 3

#include<iostream>

#include<algorithm>

#include<string>

#include<vector>

#include<cmath>

#include<fstream>

using namespace std;

int main()

{

 int i,n,d,temp,sum1,sum2;

 vector<int> v;

// fstream cin("1176、txt");

 while (cin>>n)

 {

  v、clear();

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

  {

   cin>>temp;

   v、push_back(temp);

  }

  

  cin>>d;

  

  sum1=pow(2,d-1) 1;

  sum2=pow(2,d) 1;

  if (sum1>=n)

  {

   cout<<"EMPTY"<<endl;

  }

  else if (n>sum1&&n<sum2)

  {

   cout<<v、at(sum1);

   for (i=sum1+1;i<n;i++)

   {

    cout<<" "<<v、at(i);

   }

  }

  else if (n>=sum2)

  {

   cout<<v、at(sum1);

   for (i=sum1+1;i<sum2;i++)

   {

    cout<<" "<<v、at(i);

   }

  }

  cout<<endl;

 }

 return 0;

}

36、 题目描述:

输入1系列整数,建立二叉排序数,并进行前序,中序,后序遍历。

输入:

输入第1行包括1个整数n(1<=n<=100)。

接下来的1行包括n个整数。

输出:

可能有多组测试数据,对于每组数据,将题目所给数据建立1个二叉排序树,并对二叉排序树进行前序、中序和后序遍历。

每种遍历结果输出1行。每行最后1个数据之后有1个空格。

样例输入:

5

1 6 5 9 8

样例输出:

1 6 5 9 8

1 5 6 8 9

5 8 9 6 1

#include <iostream>

using namespace std;

typedef struct Node

{

 int data;

 struct Node *leftchild;

 struct Node *rightchild;

}BTree,*Blink;

//前序遍历

void PreOrder(Blink head)

{

 if(head)

 {

  cout << head->data << " ";

  PreOrder(head->leftchild);

  PreOrder(head->rightchild);

 }

}

//中序遍历

void InOrder(Blink head)

{

 if(head)

 {

  InOrder(head->leftchild);

  cout << head->data << " ";

  InOrder(head->rightchild);

 }

}

//后序遍历

void PostOrder(Blink head)

{

 if(head)

 {

  PostOrder(head->leftchild);

  PostOrder(head->rightchild);

  cout << head->data << " ";

 }

}

//撤销二叉树

void deleteTree(Blink &head)

{

 if(head)

 {

  deleteTree(head->leftchild);

  deleteTree(head->rightchild);

  delete head;

 }

}

//建立二叉排序树

void buildBinarySortTree(Blink &head, int elem[], int length)

{

 Blink p,pre;

 int flagLeftOrRight;    //0表示左孩子,1表示右孩子

 int success;

 head = new BTree;   //生成头结点

 head->data = elem[0];

 head->leftchild = NULL;

 head->rightchild = NULL;

 for(int i = 1; i < length; ++i)

 {

  success = 0;

  pre = NULL;

  p = head;

  while(p)    //寻找插入的位置

  {

   pre = p;

   if(p->data == elem[i]) //查找成功

   {

    success = 1;

    break;

   }

   else if(p->data < elem[i]) //沿右孩子搜索

   {

    p = p->rightchild;

    flagLeftOrRight = 1;

   }

   else    //沿左孩子搜索

   {

    p = p->leftchild;

  flagLeftOrRight = 0;

   }

  }

  

  if(!success)

  {

   p = new BTree;     //生成新结点

   p->data = elem[i];

   p->leftchild = NULL;

   p->rightchild = NULL;

   

   if(flagLeftOrRight == 0)  //新插入的结点作为左孩子

   {

    pre->leftchild = p;

   }

   else if(flagLeftOrRight == 1) //新插入的结点作为右孩子

   {

    pre->rightchild = p;

   }

  }

 }

}

int main()

{

 int N;

 int elem[110];

 Blink head;

 while(cin >> N)

 {

  for(int i = 0; i < N; ++i)

  {

   cin >> elem[i];

  }

  

 buildBinarySortTree(head,elem,N); 

  

  PreOrder(head);

  cout << endl;

  InOrder(head);

  cout << endl;

  PostOrder(head);

  cout << endl;

 }

 return 0;

}

37、 题目描述:

判断两序列是否为同1二叉搜索树序列

输入:

开始1个数n,(1<=n<=20) 表示有n个需要判断,n= 0 的时候输入结束。

接下去1行是1个序列,序列长度小于10,包含(0~9)的数字,没有重复数字,根据这个序列可以构造出1颗二叉搜索树。

接下去的n行有n个序列,每个序列格式跟第1个序列1样,请判断这两个序列是否能组成同1颗二叉搜索树。

输出:

如果序列相同则输出YES,否则输出NO

样例输入:

2

567432

543267

576342

0

样例输出:

YES

NO

#include<iostream>

using namespace std;

int a[1024];

int b[1024];

void createtree(string s,int c[])

{

int len=s、length();

for(int i=0;i<len;i++)

{

 int temp=s[i]-'0';

 for(int j=1;j<=1023;)

 {

     if(c[j]==-1)

     {c[j]=temp;break;}

     else if(c[j]>temp)

     j=j*2;

     else

     j=j*2+1;

 }

} 

}

int main()

{

int n,i;

string s;

string t;

while(cin>>n&&n)

{

 for(i=0;i<1024;i++) a[i]=-1;

 cin>>s;

 createtree(s,a);

 while(n--)

 {

     for(i=0;i<1024;i++) b[i]=-1;

     cin>>t;

     createtree(t,b);

     for(i=0;i<1024;i++)

     if(a[i]!=b[i]) break;

     if(i==1024)

     cout<<"YES"<<endl;

     else

     cout<<"NO"<<endl; 

 }

}

return 0;

}

38、 题目描述:

读入两个小于10000的正整数A和B,计算A+B。需要注意的是:如果A和B的末尾K(不超过8)位数字相同,请直接输出-1。

输入:

测试输入包含若干测试用例,每个测试用例占1行,格式为"A B K",相邻两数字有1个空格间隔。当A和B同时为0时输入结束,相应的结果不要输出。

输出:

对每个测试用例输出1行,即A+B的值或者是-1。

样例输入:

1 2 1

11 21 1

108 8 2

36 64 3

0 0 1

样例输出:

3

-1

-1

100

#include<iostream>

#include<string>

#include<fstream>

#include<algorithm>

using namespace std;

void split(int num,int k,char *str)

{

 int i;

 for (i=0;i<k;i++)

 {

  str[i]=num%10;

  num/=10;

 }

 str[i]='\0';

}

int main()

{

 int a,b,k;

 char cha[10],chb[10];

 //fstream cin("1015、txt");

 while (cin>>a>>b,a+b)

 {

  cin>>k;

  split(a,k,cha);

  split(b,k,chb);

  string stra(cha);

  string strb(chb);

  if (stra==strb)

  {

   

   cout<<"-1"<<endl;

  }

  else

  {

   cout<<a+b<<endl;

  }

 }

 return 0;

}

39、 题目描述:

守形数是这样1种整数,它的平方的低位部分等于它本身。

比如25的平方是625,低位部分是25,因此25是1个守形数。

编1个程序,判断N是否为守形数。

输入:

输入包括1个整数N,2<=N<100。

输出:

可能有多组测试数据,对于每组数据,

输出"Yes!”表示N是守形数。

输出"No!”表示N不是守形数。

样例输入:

25

4

样例输出:

Yes!

No!

#include<stdio、h>

#include<stdlib、h>

#include<string、h>

int n, t;

int main() {

while(~scanf("%d", &n)) {

 t = n * n;

 while(n > 0) {

     if((n % 10) != (t % 10)) break;

     n /= 10;

     t /= 10;

 }

 if(!n) puts("Yes!");

 else

     puts("No!");

}

return 0;

}

40、 题目描述:

写个算法,对2个小于1000000000的输入,求结果。

特殊乘法举例:123 * 45 = 1*4 +1*5 +2*4 +2*5 +3*4+3*5

输入:

两个小于1000000000的数

输出:

输入可能有多组数据,对于每1组数据,输出Input中的两个数按照题目要求的方法进行运算后得到的结果。

样例输入:

123 45

样例输出:

54

#include <iostream>

#include <string>

using namespace std;

int main()

{

 string str1,str2;

 while(cin>>str1>>str2)

 {

  int sum=0;

  for(int i=0;i<str1、size();i++)

   for(int j=0;j<str2、size();j++)

   { 

    sum+=(str1[i]-48)*(str2[j]-48);

   }

   cout<<sum<<endl;

 }

 return 0;

}

41、 题目描述:

设N是1个四位数,它的9倍恰好是其反序数(示例:1234的反序数是4321)

求N的值

输入:

程序无任何输入数据

输出:

输出题目要求的四位数,如果结果有多组,则每组结果之间以回车隔开

样例输入:

样例输出:

#include <cstdio>

#include <iostream>

using namespace std;

// 将1个数反转

int GetReverseNum(int a)

{

 int t = 1000;

 int p = 1;

 int ans = 0;

 for (int i=1; i<=4; i++)

 {

  ans += a / t * p;

  a %= t;

  t /= 10;

  p *= 10;

 }

 return ans;

}

int main()

{

 for (int i=1000; i<=1111; i++)

 {

  int t = i * 9;

  if (GetReverseNum(i) == t)

  {

   printf("%d\n", i);

  }

 }

 return 0;

}

42、 题目描述:

打印所有不超过n(n<256)的,其平方具有对称性质的数。

如11*11=121

输入:

无任何输入数据

输出:

输出具有题目要求的性质的数。如果输出数据不止1组,各组数据之间以回车隔开。

样例输入:

样例输出:

#include<stdio、h>

int main()

{

int n=256,a[5],b,m,c[256],p=0;

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

{

  int flag=0;

  m=0;

  b=i*i;

  while(b!=0)

  {

     a[m++]=b%10;

     b=(b-a[m-1])/10;

  }

  for(int j=0;j<m/2;j++)

     if(a[j]!=a[m-1-j]){ flag=1;   break;}

  if(flag==0) printf("%d\n",i);

}

return 0;

}

43、 题目描述:

The digital root of a positive integer is found by summing the digits of the integer、 If the resulting value is a single digit then that digit is the digital root、 If the resulting value contains two or more digits, those digits are summed and the process is repeated、 This is continued as long as necessary to obtain a single digit、

For example, consider the positive integer 24、 Adding the 2 and the 4 yields a value of 6、 Since 6 is a single digit, 6 is the digital root of 24、 Now consider the positive integer 39、 Adding the 3 and the 9 yields 12、 Since 12 is not a single digit, the process must be repeated、 Adding the 1 and the 2 yeilds 3, a single digit and also the digital root of 39、

输入:

The input file will contain a list of positive integers, one per line、

The end of the input will be indicated by an integer value of zero、

输出:

For each integer in the input, output its digital root on a separate line of the output、

样例输入:

24

39

0

样例输出:

6

3

#include <iostream>

#include <string>

using namespace std;

string getRoot(string s){

int v = 0;

for(int i=0;i<s、length();i++){

 v += s[i] - '0';

}

int t = v,tmp;

string res;

res、resize(0);

while(t!=0){

 tmp = t%10;

 res、push_back('0'+tmp);

 t /= 10;

}

if(res、size()==1){

 return res;

}

else{

 return getRoot(res);

}

}

int main(int argc,char* argv[]){

string s;

while(cin>>s&&s!="0"){

 cout<<getRoot(s)<<endl;

}

return 0;

}

44、 题目描述:

输入两个不超过整型定义的非负10进制整数A和B(<=231-1),输出A+B的m (1 < m <10)进制数。

输入:

输入格式:测试输入包含若干测试用例。每个测试用例占1行,给出m和A,B的值。

当m为0时输入结束。

输出:

输出格式:每个测试用例的输出占1行,输出A+B的m进制数。

样例输入:

8 1300 48

2 1 7

0

样例输出:

2504

1000

#include <iostream>

#include <string>

using namespace std;

int main()

{

unsigned int m,a,b;

unsigned long int sum;

unsigned int stack[1000];

int top=-1;

while(cin>>m)

{

if(m==0)

return 0;

cin>>a>>b;

sum=a+b;

if(sum==0)

stack[++top]=0;

while(sum!=0)

{

stack[++top]=sum%m;

sum=sum/m;

}

while(top!=-1)

cout<<stack[top--];

cout<<""<<endl;

}

return 1;

}

45、 题目描述:

求任意两个不同进制非负整数的转换(2进制~16进制),所给整数在long所能表达的范围之内。

不同进制的表示符号为(0,1,、、、,9,a,b,、、、,f)或者(0,1,、、、,9,A,B,、、、,F)。

输入:

输入只有1行,包含三个整数a,n,b。a表示其后的n 是a进制整数,b表示欲将a进制整数n转换成b进制整数。a,b是十进制整数,2 =< a,b <= 16。

数据可能存在包含前导零的情况。

输出:

可能有多组测试数据,对于每组数据,输出包含1行,该行有1个整数为转换后的b进制数。输出时字母符号全部用大写表示,即(0,1,、、、,9,A,B,、、、,F)。

样例输入:

15 Aab3 7

样例输出:

210306

#include <iostream>

#include <string>

#include <cmath>

using namespace std;

int main()

{

 int a,b;

 long n=0;

 string str;

 while(cin>>a&&a>=2&&a<=16)

 {

  cin>>str>>b;

  int size=str、size() 1;

  for(string::iterator i=str、begin();i!=str、end();i++)

  {

   if(*i>64&&*i<71)n+=(*i-55)*pow(a,size--);

   else if(*i>96&&*i<103)n+=(*i-87)*pow(a,size--);

   else n+=(*i-48)*pow(a,size--);

  }

  str="";

  char ch='0';int tmp=0;

  if(n!=0)while(n)

  {

   tmp=n%b;

   if(tmp>9)ch=tmp-10+'A';

   else ch=tmp+'0';

   str+=ch;

   n/=b;

  }

  else str="0";

  for(string::iterator j=str、end() 1;j>=str、begin();j--)

  cout<<*j;

  cout<<endl;

 }

 return 0;

}

46、 题目描述:

将1个长度最多为30位数字的十进制非负整数转换为二进制数输出。

输入:

多组数据,每行为1个长度不超过30位的十进制非负整数。

(注意是10进制数字的个数可能有30个,而非30bits的整数)

输出:

每行输出对应的二进制数。

样例输入:

0

1

3

8

样例输出:

0

1

11

1000

#include <iostream>

#include <cstdio>

#include <cstring>

#include <bitset>

using namespace std;

int main(){

 int i,j,num[40],len,c,tmp,len_res;

 char s[40],res[200];

// freopen("1、txt","r",stdin);

// freopen("out、txt","r",stdout);

 while (scanf("%s",s)!=EOF)

 {

  for (len=0;s[len];len++)

  {

   num[len]=s[len]-'0';

  }

  //跳出循环后长度也就出来了

  i=0;

  len_res=0;

  while (i<len)

  {

   res[len_res++]=num[len-1]%2+'0';

   //这里是转化为2进制,只用最后1位来除2余数就可以了,其他高位对除2余数不影响,因为从高位借过1位来总是能被2整除,

   c=0;//借位

   for (j=i;j<len;j++)

   {

    tmp=num[j];

    num[j]=(num[j]+c)/2;

    if (tmp&1)//当这1位是奇数的时候表示不能整除2,要借位了

    {

     c=10;

    }else{

     c=0;

    }

   }

   if (num[i]==0)//可能前几次不为0,再循环

   {

    i++;

   }

  }

  for (i=len_res-1;i>=0;i--)//逆向输出

  {

   printf("%c",res[i]);

  }

  printf("\n");

 }

// fclose(stdout);

// fclose(stdin);

 return 0;

}

47、 题目描述:

输入1个整数,将其转换成八进制数输出。

输入:

输入包括1个整数N(0<=N<=100000)。

输出:

可能有多组测试数据,对于每组数据,

输出N的八进制表示数。

样例输入:

7

8

9

样例输出:

7

10

11

#include<stdio、h>

#include<stdlib、h>

#include<string、h>

int main()

{

int n;

while(~scanf("%d",&n))

{

  int num[10];

  memset(num,0,sizeof(num));

  int i=0;

  if(n==0)

   printf("0\n");

  else

  {

   while(n)

   {

  num[i++]=n%8;

  n=n/8;

   }

   for(int j=i-1;j>=0;j--)

   if(j==0)printf("%d\n",num[j]);

   else printf("%d",num[j]);

  }

}

return 0;

}

48、 题目描述:

输入两个正整数,求其最大公约数。

输入:

测试数据有多组,每组输入两个正整数。

输出:

对于每组输入,请输出其最大公约数。

样例输入:

49 14

样例输出:

7

#include <iostream>

#include <fstream>

using namespace std;

int main(){

   // ifstream cin("input、txt");

 int a,b,temp;

 while(cin>>a>>b)

 {

   while(b>0)

   {

    a=a%b;

    temp=b;

    b=a;

    a=temp;

   }

   cout<<a<<endl;

  }

}

49、 题目描述:

给定两个正整数,计算这两个数的最小公倍数。

输入:

输入包含多组测试数据,每组只有1行,包括两个不大于1000的正整数。

输出:

对于每个测试用例,给出这两个数的最小公倍数,每个实例输出1行。

样例输入:

10 14

样例输出:

70

#include<stdio、h>

int gcd(int a,int b )

{

 return b!=0 ? gcd(b,a%b) :a;

}

int main()

{

 int a,b;

 while(scanf("%d%d",&a,&b)!=EOF)

   printf("%d\n",a*b/gcd(a,b));

 return 0;

}题目描述:

The least common multiple (LCM) of a set of positive integers is the smallest positive integer which is divisible by all the numbers in the set、 For example, the LCM of 5, 7 and 15 is 105、

输入:

Input will consist of multiple problem instances、 The first line of the input will contain a single integer indicating the number of problem instances、 Each instance will consist of a single line of the form m n1 n2 n3 、、、 nm where m is the number of integers in the set and n1 、、、 nm are the integers、 All integers will be positive and lie within the range of a 32-bit integer、

输出:

For each problem instance, output a single line containing the corresponding LCM、 All results will lie in the range of a 32-bit integer、

样例输入:

2

3 5 7 15

6 4 10296 936 1287 792 1

样例输出:

105

10296

50、

#include "cstdio"

#include "cstring"

int gcd(int a,int b){

if(b==0) return a;

else return gcd(b,a%b);

}

int main(){

int n;

scanf("%d",&n);

while(n--){

 int c;

 scanf("%d",&c);

 int tmp,k=0;

 while(c--){

     scanf("%d",&tmp);

     if(k==0) k=tmp;

     else k=k/gcd(k,tmp)*tmp;

 }

 printf("%d\n",k);

}

return 0;

}

51、 题目描述:

给定1个数n,要求判断其是否为素数(0,1,负数都是非素数)。

输入:

测试数据有多组,每组输入1个数n。

输出:

对于每组输入,若是素数则输出yes,否则输入no。

样例输入:

13

样例输出:

Yes

#include <iostream>

#include <cmath>

using namespace std;

int N;

void solve()

{

 if(N<=1){cout<<"no"<<endl;return;}

 else

 {

  int M =(int)sqrt((double)N);

  for(int i = 2; i<=M; i++)

   if(N%i == 0)

   {

    cout<<"no"<<endl;

    return;

   }

 }

 cout<<"yes"<<endl;

}

int main()

{

 while(cin>>N)

 {

  solve();

 }

 return 0;

}

52、 题目描述:

输入1个整数n(2<=n<=10000),要求输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数,如果没有则输出-1。

输入:

输入有多组数据。

每组1行,输入n。

输出:

输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数(素数之间用空格隔开,最后1个素数后面没有空格),如果没有则输出-1。

样例输入:

100

样例输出:

11 31 41 61 71

#include<iostream>

#include<vector>

#include<cmath>

using namespace std;

bool IsPrime(int num)

{

 bool flag = true;

 for(int i=2;i<=(int)sqrt((double)num);i++)

  if(num%i==0)

  {

   flag = false;

   break;

  }

  return flag;

}

int main()

{

 int n;

 vector<int> val;

 while(cin>>n)

 {

  if(n<=10)

   cout<<"-1"<<endl;

  else{

   val、clear();

   for(int i=11;i<n;i=i+10)

    if(IsPrime(i))

     val、push_back(i);

   for(size_t ind=0;ind<val、size() 1;ind++)

    cout<<val[ind]<<' ';

   cout<<val[val、size() 1]<<endl;

  }

 }

 return 0;

}

53、 题目描述:

Output the k-th prime number、

输入:

k≤10000

输出:

The k-th prime number、

样例输入:

3

7

样例输出:

5

17

#include<iostream>

#include<malloc、h>

#include<stdio、h>

using namespace std;

int main()

{

int *Isprime;

int i,j,k,m,z;

int N=200000,count;

Isprime=(int*)malloc((N+1)*sizeof(int));

for(int n=0;n!=N;n++)

{

Isprime[n]=1;

}

for(i=0;i!=N;i++)

{

if(i%2==0)

{

Isprime[i]=0;

}

}

Isprime[2]=1;

Isprime[1]=0;

for(j=3;j*j<N;j++)

{

if(Isprime[j]==1)

{

for(k=j+1;k<N;k++)

{

if(k!=j&&k%j==0)

{

Isprime[k]=0;

}

}

}

}

while(cin>>z)

{

count=0;

for(m=0;m!=N;m++)

{

if(Isprime[m]==1)

{

count++;

if(count==z)

break;

}

}

cout<<m<<endl;

}

return 0;

}

54、 题目描述:

Goldbach's Conjecture: For any even number n greater than or equal to 4, there exists at least one pair of prime numbers p1 and p2 such that n = p1 + p2、

This conjecture has not been proved nor refused yet、 No one is sure whether this conjecture actually holds、 However, one can find such a pair of prime numbers, if any, for a given even number、 The problem here is to write a program that reports the number of all the pairs of prime numbers satisfying the condition in the conjecture for a given even number、

A sequence of even numbers is given as input、 Corresponding to each number, the program should output the number of pairs mentioned above、 Notice that we are interested in the number of essentially different pairs and therefore you should not count (p1, p2) and (p2, p1) separately as two different pairs、

输入:

An integer is given in each input line、 You may assume that each integer is even, and is greater than or equal to 4 and less than 2^15、 The end of the input is indicated by a number 0、

输出:

Each output line should contain an integer number、 No other characters should appear in the output、

样例输入:

6

10

12

0

样例输出:

1

2

1

#include <stdio、h>

#include <math、h>

bool mark[33001];

void init()

{

for( int i = 2; i <= 32770; i ++ )

 mark[i] = false;

for( int i = 2; i <= 32770; i ++ ) {

 if( !mark[i] ) {

     for( int j = i * i; j <= 32770; j += i )

  mark[j] = true;

 }

}

}

int main()

{

init();

int n;

while (scanf("%d", &n) != EOF && n != 0 ) {

 int cnt = 0;

 for( int i = 2; i <= n / 2; i ++ )

     if( !mark[i] && !mark[n - i] )

  cnt ++ ;

 printf("%d\n", cnt);

}

return 0;

}

55、题目描述:

求正整数N(N>1)的质因数的个数。

相同的质因数需要重复计算。如120=2*2*2*3*5,共有5个质因数。

输入:

可能有多组测试数据,每组测试数据的输入是1个正整数N,(1<N<10^9)。

输出:

对于每组数据,输出N的质因数的个数。

样例输入:

120

样例输出:

5

#include <iostream>

#include <cstdio>

#include <string>

#include <cstring>

#include <cctype>

#include <cstdlib>

#include <string、h>

#include <algorithm>

#include <cmath>

using namespace std;

int main()

{

int n,ans,i;

while(scanf("%d",&n) == 1)

{

    ans = 0;

    for(i = 2;i <= sqrt(n);i++)

      if(n % i == 0)

      {

        while(n%i == 0)

        {

       ans ++;

       n = n / i;

        }

      }

    if(n > 1)

     ans ++;

    printf("%d\n",ans);

}

return 0;

}

56、 题目描述:

给定n,a求最大的k,使n!可以被a^k整除但不能被a^(k+1)整除。

输入:

两个整数n(2<=n<=1000),a(2<=a<=1000)

输出:

1个整数、

样例输入:

6 10

样例输出:

1

#include <iostream>

using namespace std;

#define MAXSIZE 500

int main() {

 int n, a;

 while(cin >> n && cin >> a){

  int minDivisor[MAXSIZE];

  int countMinDiv[MAXSIZE];

  int countDiv = 0;

  int temA = a;

  for(int i = 2; i<=temA; i++){

   if(temA%i == 0){

    minDivisor[countDiv] = i;

    countMinDiv[countDiv] = 0;

    while(temA%i == 0){

     temA /= i;

     countMinDiv[countDiv]++;

    }

    countDiv++;

   }

  }

  int k = 0, count = 0;

  for(int j=0; j<countDiv; j++){

   count = 0;

   for(int i=2; i<=n; i++){

    int tem = i;

    while(tem%minDivisor[j] == 0){

     count++;

     tem /= minDivisor[j];

    }

   }

   countMinDiv[j] = count/countMinDiv[j];

  }

  k = countMinDiv[0];

  for(int i=1; i<countDiv; i++){

   if(countMinDiv[i] < k){

    k = countMinDiv[i];

   }

  }

  cout << k <<endl;

 }

 return 0;

}

57、 题目描述:

输入n个整数,依次输出每个数的约数的个数

输入:

输入的第1行为N,即数组的个数(N<=1000)

接下来的1行包括N个整数,其中每个数的范围为(1<=Num<=1000000000)

当N=0时输入结束。

输出:

可能有多组输入数据,对于每组输入数据,

输出N行,其中每1行对应上面的1个数的约数的个数。

样例输入:

5

1 3 4 6 12

样例输出:

1

2

3

4

6

#include <iostream>

#include <cstdio>

#include <cmath>

using namespace std;

const int MAX = 1000 + 5;

int a[MAX];

int main()

{

 int n, m;

 int i, j;

 while (scanf("%d", &n) != EOF)

 {

  for (j=0; j<n; j++)

  {

   scanf("%d", &m);

   int ans = 0;

   int t = sqrt(m * 1、0);

   for (i=1; i<=t; i++)

   {

    if (m % i == 0)

    {

     (m / i == i)? ans++ : ans += 2;

    }

   }

   printf("%d\n", ans);

  }

 }

 return 0;

}

58、 题目描述:

求A^B的最后三位数表示的整数。说明:A^B的含义是“A的B次方”

输入:

输入数据包含多个测试实例,每个实例占1行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。

输出:

对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占1行。

样例输入:

2 3

12 6

6789 10000

0 0

样例输出:

8

984

1

#include <stdio、h>

int main()

{

int a,b;

while(scanf("%d%d",&a,&b)!=EOF){

 if(a==0&&b==0) break;

 int ans=1;

 while(b!=0){

     if(b%2==1){

  ans*=a;

  ans%=1000;

     }

     b/=2;

     a*=a;

     a%=1000;

 }

 printf("%d\n",ans);

}

return 0;

}

59、 题目描述:

Xinlv wrote some sequences on the paper a long time ago, they might be arithmetic or geometric sequences、 The numbers are not very clear now, and only the first three numbers of each sequence are recognizable、 Xinlv wants to know some numbers in these sequences, and he needs your help、

输入:

The first line contains an integer N, indicting that there are N sequences、 Each of the following N lines contain four integers、 The first three indicating the first three numbers of the sequence, and the last one is K, indicating that we want to know the K-th numbers of the sequence、

You can assume 0 < K <= 10^9, and the other three numbers are in the range [0, 2^63)、 All the numbers of the sequences are integers、 And the sequences are non-decreasing、

输出:

Output one line for each test case, that is, the K-th number module (%) 200907、

样例输入:

2

1 2 3 5

1 2 4 5

样例输出:

5

16

#include <stdio、h>

int main()

{

int n;

while(scanf("%d",&n)!=EOF)

{

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

{

 long long a,b,c,k,ans;

 scanf("%lld%lld%lld%lld",&a,&b,&c,&k);

 if(a+c==b*2)

 {

     ans=a+(c-b)*(k-1);

     ans%=200907;

 }else{

     long long tmp=(b/a)%200907;

     ans=a%200907;

     k=k-1;

     while(k!=0)

     {

  if(k%2==1)

  {

      ans*=tmp;

      ans%=200907;

  }

  k/=2;

  tmp*=tmp;

  tmp%=200907;

     }

 }

 printf("%lld\n",ans);

}

}

return 0;

}

60、 题目描述:

A为1个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973。

输入:

数据的第1行是1个T,表示有T组数据。

每组数据的第1行有n(2 <= n <= 10)和k(2 <= k < 10^9)两个数据。接下来有n行,每行有n个数据,每个数据的范围是[0,9],表示方阵A的内容。

输出:

对应每组数据,输出Tr(A^k)%9973。

样例输入:

2

2 2

1 0

0 1

3 99999999

1 2 3

4 5 6

7 8 9

样例输出:

2

2686

#include<stdio、h>

int a[11][11],ans[11][11];

void f(int a[11][11],int b[11][11],int n){

int i,j,k,c[11][11];

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

 for(j=0;j<n;j++)c[i][j]=0;

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

 for(j=0;j<n;j++){

    for(k=0;k<n;k++)c[i][j]=(c[i][j]%9973+a[i][k]*b[k][j]%9973)%9973;

 }

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

 for(j=0;j<n;j++)a[i][j]=c[i][j];

}

int main(){

int t,n,k,i,j,sum;

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

 while(t--!=0){

     scanf("%d%d",&n,&k);

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

  for(j=0;j<n;j++){

      scanf("%d",&a[i][j]);

      ans[i][j]=0;

      if(i==j)

      ans[i][j]=1;

  }

     while(k){

  int x=k%2;

  if(x==1){

      f(ans,a,n);

  }

  f(a,a,n);

  k/=2;

     }

     for(i=0,sum=0;i<n;i++){

  sum=(sum%9973+ans[i][i]%9973)%9973;

     }

     printf("%d\n",sum);

 }

}

return 0;

}

61、 题目描述:

实现1个加法器,使其能够输出a+b的值。

输入:

输入包括两个数a和b,其中a和b的位数不超过1000位。

输出:

可能有多组测试数据,对于每组数据,

输出a+b的值。

样例输入:

2 6

10000000000000000000 10000000000000000000000000000000

样例输出:

8

10000000000010000000000000000000

#include <stdio、h>

#include <string、h>

#define MAXN 1000+10

char a[MAXN];

char b[MAXN];

int main(){

 int n,m,i,s;

   while(scanf("%s%s",a,b)==2){

  

    int c[MAXN]={0};

    int d[MAXN]={0};

    int sum[MAXN]={0};

// printf("%s %s\n",a,b);

 n=strlen(a);

 m=strlen(b);

  int cin =0;

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

  

 c[n-i-1]=a[i]-'0';

 }

 for(i=0;i<m;i++){

 d[m-i-1]=b[i]-'0';

 }

 for(i=0;i<MAXN;i++){

  s=c[i]+d[i]+cin;

  sum[i]=s%10;

  cin=s/10;

   }

 for(i=MAXN-1;i>=0;i--){

  if(i!=0){

  if(!(sum[i]==0))

  { 

  

  int j;

  for(j=i;j>=0;j--)

  {

   printf("%d",sum[j]);  

  }

  i=-1;

  

  }

  }

  else{

     if(sum[i]==0) printf("0");

     else printf("%d",sum[0]);

  }

 }

printf("\n");

 }

return 0;

}

63、 题目描述:

输入1个正整数N,输出N的阶乘。

输入:

正整数N(0<=N<=1000)

输出:

输入可能包括多组数据,对于每1组输入数据,输出N的阶乘

样例输入:

4

5

15

样例输出:

24

120

1307674368000

#include "cstdio"

#include "cstring"

#include "cstdlib"

int res[10010];

int main()

{

int n;

while (scanf("%d", &n) == 1)

{

 int i, j;

 memset(res, 0, sizeof(res));

 res[0] = 1;

 res[1] = 1;

 for (i = 2; i <= n; i++)

 {

     for (j = 1; j <= res[0]; j++)

  res[j] = res[j] * i;

  

     for (j = 1; j <= res[0]; j++)

     {

  if (res[j] >= 10)

  {

      res[j+1] += res[j] / 10;

      res[j] %= 10;

      if (j == res[0])

   res[0]++;

  }

     }

 }

 for (i = res[0]; i >= 1; i--)

     printf("%d", res[i]);

 printf("\n");

}

return 0;

}

64、 题目描述:

将M进制的数X转换为N进制的数输出。

输入:

输入的第1行包括两个整数:M和N(2<=M,N<=36)。

下面的1行输入1个数X,X是M进制的数,现在要求你将M进制的数X转换成N进制的数输出。

输出:

输出X的N进制表示的数。

样例输入:

16 10

F

样例输出:

15

提示:

输入时字母部分为大写,输出时为小写,并且有大数据。

来源:

#include<iostream>

#include<string、h>

#include<string>

#include<ctype、h>

#include<math、h>

#include<algorithm>

#include<cstdio>

using namespace std;

int M,N;

char a[10000];

string quotient_handle(const string& s1 )

{

 string temp="";

 string::size_type index=s1、find_first_not_of('0');

 if(index==string::npos)

  ;

 else

  temp、assign(s1,index,s1、length() index);

 return temp;

}

int main()

{

 while(scanf("%d %d %s",&M,&N,&a)!=EOF)

 {

  string quotient="";;

  string div(a);

  int temp=0;

  while(div!="")

  {

   string div_temp="";

   for(int i=0,index=0;i<div、length();i++)

   {

    int digit_temp=0;

    if(isdigit(div[i]))

     digit_temp=(div[i]-'0')+(temp*M);

    else

     digit_temp=(div[i]-'A'+10)+(temp*M);

    div_temp+=(digit_temp/N)<10? digit_temp/N+'0': digit_temp/N-10+'A';

    temp=digit_temp%N;

   }

   quotient+=(temp)<10? temp+'0' : temp-10+'a';

   div=quotient_handle(div_temp);

   temp=0;

  }

  reverse(quotient、begin(),quotient、end());

  cout<<quotient<<endl;

 }

 return 0;

}

65、 题目描述:

求2个浮点数相加的和

题目中输入输出中出现浮点数都有如下的形式:

P1P2、、、Pi、Q1Q2、、、Qj

对于整数部分,P1P2、、、Pi是1个非负整数

对于小数部分,Qj不等于0

输入:

对于每组案例,第1行是测试数据的组数n,每组测试数据占2行,分别是两个加数。

每组测试数据之间有1个空行,每行数据不超过100个字符

输出:

每组案例是n行,每组测试数据有1行输出是相应的和。

输出保证1定是1个小数部分不为0的浮点数

样例输入:

2

0、111111111111111111111111111111

0、111111111111111111111111111111

10000000、655555555555555555555555555555

1、444444444444444444444444444445

样例输出:

0、222222222222222222222222222222

10000002、1

#include <iostream>

#include <string、h>

using namespace std;

char addOne137[1000];

char addTwo137[1000];

char result137[1000];

int doubleAdd137()

{

int len1 = strlen( addOne137 );

int len2 = strlen( addTwo137 );

//if ( len1 == len2 && len1 == 3 )

//{

// if ( addOne137[0] == '0' && addTwo137[0] =='0' && addOne137[2] == '0' && addTwo137[2] == '0')

// {

// //strcpy(result137,addOne137);

// result137[0] = '0';

// result137[1] = '\0';

// return 3;

// }

//}

int point1 = 0;

while( addOne137[point1] != '、')

point1++;

int point2 = 0;

while( addTwo137[point2] != '、')

point2++;

int i = len1 -1;

int j = len2 -1;

int pos = 0;

while( i - point1 > j - point2)

result137[pos++] = addOne137[i--];

while( j - point2 > i - point1)

result137[pos++] = addTwo137[j--];

int d = 0;

int cur;

int point;

while ( i>=0 && j>=0 )

{

if ( addOne137[i] == '、')

{

i--;

j--;

point = pos;

result137[pos++] = '、';

continue;

}

cur = addOne137[i--] + addTwo137[j--] -'0' -'0' + d;

result137[pos++] = cur % 10 + '0';

d = cur / 10;

}

while ( i>=0 )

{

cur = addOne137[i--] - '0' + d;

result137[pos++] = cur % 10 + '0';

d = cur / 10;

}

while ( j >= 0 )

{

cur = addTwo137[j--] - '0' + d;

result137[pos++] = cur % 10 + '0';

d = cur / 10;

}

while ( d > 0 )

{

result137[pos++] = d % 10 + '0';

d = d / 10;

}

result137[pos] = '\0';

int start = 0;;

while( start < point -1 && result137[start] == '0')

{

start ++;

pos--;

}

strcpy(result137,result137+start);

for ( int i=0; i< pos/2; i++)

{

char c = result137[i];

result137[i] = result137[pos-1-i] ;

result137[pos-1-i] = c;

}

return pos;

}

int main()

{

int n;

cin >> n;

while ( n-- )

{

cin >> addOne137 >> addTwo137;

doubleAdd137();

cout << result137 << endl;

}

return 0;

}

66、 题目描述:

对N个长度最长可达到1000的数进行排序。

输入:

输入第1行为1个整数N,(1<=N<=100)。

接下来的N行每行有1个数,数的长度范围为1<=len<=1000。

每个数都是1个正数,并且保证不包含前缀零。

输出:

可能有多组测试数据,对于每组数据,将给出的N个数从小到大进行排序,输出排序后的结果,每个数占1行。

样例输入:

3

11111111111111111111111111111

2222222222222222222222222222222222

33333333

样例输出:

33333333

11111111111111111111111111111

2222222222222222222222222222222222

#include<stdio、h>

#include<stdlib、h>

#include<string、h>

#include<algorithm>

using namespace std;

struct cha{

   char num[1010];

   };

bool cmp(struct cha cha1,struct cha cha2){

 if(strlen(cha1、num)==strlen(cha2、num))//WA*1,设计比较算法的时候误将两个string数组strcmp比较是否

      //相等作为边界条件

     return strcmp(cha1、num,cha2、num)<0;

 else

     return strlen(cha1、num)<strlen(cha2、num);

 }

int main()

{

  int n;

  while(~scanf("%d",&n))

  {

   struct cha cha1[n];

   for(int i=0;i<=n-1;i++)

  scanf("%s",&cha1[i]、num);

  

   sort(cha1,cha1+n,cmp);

   for(int i=0;i<=n-1;i++)

  printf("%s\n",cha1[i]、num);

  }

 return 0;

}

67、 题目描述:

对于1个十进制数A,将A转换为二进制数,然后按位逆序排列,再转换为十进制数B,我们乘B为A的二进制逆序数。

示例对于十进制数173,它的二进制形式为10101101,逆序排列得到10110101,其十进制数为181,181即为173的二进制逆序数。

输入:

1个1000位(即10^999)以内的十进制数。

输出:

输入的十进制数的二进制逆序数。

样例输入:

173

样例输出:

181

#include<stdio、h>

#include<string、h>

int main()

{

 int a[1000],b[100000],c[1500],temp[1500],i,j,l,sum,remain,len,flag;//a为原数组,b为二进制,c为转换后,temp为幂次临时数组

 char cccc[1000];

 while(scanf("%s",cccc)!=EOF){memset(a,0,sizeof(a));memset(b,0,sizeof(b));memset(c,0,sizeof(c));memset(temp,0,sizeof(temp));

 l=strlen(cccc);

 for(i=0;i<l;i++)

  a[i]=cccc[i]-'0';

 if(l==1&&a[0]==0){printf("0\n");continue;}

 sum=1;

 len=0;//记录二进制数的位数#3##

 while(sum>0)//计算二进制数

 {

  

  remain=0;//记录除2的余数

  for(i=0;i<l;i++)

  {

   a[i]+=remain*10;

   remain=a[i]%2;

   a[i]=a[i]/2;

  }

  b[len]=remain;

  len++;

  for(i=0,sum=0;i<l;i++)

   sum+=a[i];

 }

 temp[0]=1;

 for(i=len-1;i>=0;i--)

 { 

  if(b[i])//若该二次项为1 则相加,否则不加

  {

   for(j=0;j<1500;j++)

    c[j]+=temp[j]; 

   for(j=0;j<1499;j++)

   {

    c[j+1]+=c[j]/10;

    c[j]=c[j]%10;

   }

  }

 for(j=0;j<1499;j++)

   temp[j]=temp[j]*2;

   for(j=0;j<1499;j++)

   {

    temp[j+1]+=temp[j]/10;

    temp[j]=temp[j]%10;

   }

 } 

 flag=0;

 for(j=1499;j>=0;j--)

 {

  if(flag==1)

   printf("%d",c[j]);

  else if(c[j]>0)

  {

   flag=1;

   printf("%d",c[j]);

  }

 }

 printf("\n");

 }

 return 1;

}

68、 题目描述:

某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇。省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不1定有直接的道路相连,只要互相间接通过道路可达即可)。问最少还需要建设多少条道路?

输入:

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是城镇数目N ( < 1000 )和道路数目M;随后的M行对应M条道路,每行给出1对正整数,分别是该条道路直接连通的两个城镇的编号。为简单起见,城镇从1到N编号。

注意:两个城市之间可以有多条道路相通,也就是说

3 3

1 2

1 2

2 1

这种输入也是合法的

当N为0时,输入结束,该用例不被处理。

输出:

对每个测试用例,在1行里输出最少还需要建设的道路数目。

样例输入:

4 2

1 3

4 3

3 3

1 2

1 3

2 3

5 2

1 2

3 5

999 0

0

样例输出:

1

0

2

998

#include<iostream>

#include<algorithm>

#include<cstring>

#include<cstdio>

#include<cstdlib>

using namespace std;

int fa[1000];

int getfa(int i)

{

if(fa[i]==i)

return i;

else

fa[i]=getfa(fa[i]);

return fa[i];

}

int main()

{

int n,m;

int i,j;

int road;

int a,b;

while(cin>>n&&n)

{

for(int i=1;i<=n;i++)

fa[i]=i;

cin>>m;

while(m--)

{

cin>>a>>b;

fa[getfa(b)]=getfa(a);

}

road=0;

for(i=1;i<=n;i++)

{

for(j=1;j<=n;j++)

{

if(getfa(i)!=getfa(j))

{

 fa[getfa(j)]=getfa(i);

 road++;

}

}

}

cout<<road<<endl;

}

return 0;

}

67、 题目描述:

Mr Wang wants some boys to help him with a project、 Because the project is rather complex, the more boys come, the better it will be、 Of course there are certain requirements、Mr Wang selected a room big enough to hold the boys、 The boy who are not been chosen has to leave the room immediately、 There are 10000000 boys in the room numbered from 1 to 10000000 at the very beginning、 After Mr Wang's selection any two of them who are still in this room should be friends (direct or indirect), or there is only one boy left、 Given all the direct friend-pairs, you should decide the best way、

输入:

The first line of the input contains an integer n (0 ≤ n ≤ 100 000) - the number of direct friend-pairs、 The following n lines each contains a pair of numbers A and B separated by a single space that suggests A and B are direct friends、 (A ≠ B, 1 ≤ A, B ≤ 10000000)

输出:

The output in one line contains exactly one integer equals to the maximum number of boys Mr Wang may keep、

样例输入:

4

1 2

3 4

5 6

1 6

4

1 2

3 4

5 6

7 8

样例输出:

4

2

#include <cstdio>

#include <cstring>

#include <vector>

#include <list>

#include <queue>

using namespace std;

const int MAX_SIZE=10000000;

//vector<int> edges[MAX_SIZE];

int cc[MAX_SIZE];

int cc_cnt;

int ufs_root(int n)

{

//while(cc[n]>=0)    n=cc[n];

//return n;

if(cc[n]<0)  return n;

else    return cc[n]=ufs_root(cc[n]);//路径压缩

}

int main_union()

{

int n,m;

while(scanf("%d",&m)>0)

{

 int i,j;

 n=MAX_SIZE;

 memset(cc,-1,n*sizeof(int));

 int max_cc=1;

 int src,dst;

 for(i=0;i<m;i++)

 {

     scanf("%d%d",&src,&dst);

     src--;

     dst--;

  

     src=ufs_root(src);

     dst=ufs_root(dst);

     if(src!=dst)

     {

  /*

  if(cc[src]>cc[dst])  cc[src]=dst;

  else if(cc[src]<cc[dst]) cc[dst]=src;

  else

  {

      cc[src]=dst;

      cc[dst]--;

  }*/

  if(cc[src]>=cc[dst])

  {

      cc[dst]+=cc[src];

      cc[src]=dst;

      if(-cc[dst]>max_cc)  max_cc=-cc[dst];

  }

  else

  {

      cc[src]+=cc[dst];

      cc[dst]=src;

      if(-cc[src]>max_cc)  max_cc=-cc[src];

  }

     }

 }

 printf("%d\n",max_cc);

}

return 0;

}

int main()

{

//main_bfs();

//main_dfs();

main_union();

return 0;

}

69、 题目描述:

给定1个无向图和其中的所有边,判断这个图是否所有顶点都是连通的。

输入:

每组数据的第1行是两个整数 n 和 m(0<=n<=1000)。n 表示图的顶点数目,m 表示图中边的数目。如果 n 为 0 表示输入结束。随后有 m 行数据,每行有两个值 x 和 y(0<x, y <=n),表示顶点 x 和 y 相连,顶点的编号从 1 开始计算。输入不保证这些边是否重复。

输出:

对于每组输入数据,如果所有顶点都是连通的,输出"YES",否则输出"NO"。

样例输入:

4 3

1 2

2 3

3 2

3 2

1 2

2 3

0 0

样例输出:

NO

YES

#include <memory、h>

#include <iostream>

#include <queue>

using namespace std;

#define N 1004

bool t[N][N], v[N]; //v=visited

bool BFS( int &n ){

 memset(v,0,sizeof(v));

 int i, j, count=1;

 queue<int> q;

 q、push(1); v[1] = 1; //第1个元素入队

 while( !q、empty() ){

  i = q、front(); q、pop(); //队首出队 其邻接点入队

  for( j=1; j<=n; j++ )

   if( t[i][j] && !v[j] )

    { v[j]=1; count++; q、push(j); }

 }

 if( count == n ) return 1;

 else return 0;

}

int main()

{

 int i, j, k, n, m;

 int a, b;

 while( cin >> n >> m && n ){

  for( i=1; i<=n; i++ )

   for( j=1; j<=n; j++ )

    t[i][j] = 0;

  for( i=0; i<m; i++ ){

   cin >> a >> b;

   t[a][b] = t[b][a] = 1;

  }

  if( n == 1 )

   cout << "YES\n";

  else if( m < n-1 || !BFS(n) )

   cout << "NO\n";

  else cout << "YES\n";

 }

 return 0;

}

70、 题目描述:

Today is Ignatius' birthday、 He invites a lot of friends、 Now it's dinner time、 Ignatius wants to know how many tables he needs at least、 You have to notice that not all the friends know each other, and all the friends do not want to stay with strangers、

One important rule for this problem is that if I tell you A knows B, and B knows C, that means A, B, C know each other, so they can stay in one table、

For example: If I tell you A knows B, B knows C, and D knows E, so A, B, C can stay in one table, and D, E have to stay in the other one、 So Ignatius needs 2 tables at least、

输入:

The input starts with an integer T(1<=T<=25) which indicate the number of test cases、 Then T test cases follow、 Each test case starts with two integers N and M(1<=N,M<=1000)、 N indicates the number of friends, the friends are marked from 1 to N、 Then M lines follow、 Each line consists of two integers A and B(A!=B), that means friend A and friend B know each other、 There will be a blank line between two cases、

输出:

For each test case, just output how many tables Ignatius needs at least、 Do NOT print any blanks、

样例输入:

2

5 3

1 2

2 3

4 5

5 1

2 5

样例输出:

2

4

#include<cstdio>

#define N 1010

int tree[N];

int getRoot(int x){

if(tree[x]==-1) return x;

else{

 int tmp=getRoot(tree[x]);

 tree[x]=tmp;

 return tmp;

}

}

int main(){

int t;

scanf("%d",&t);

while(t--){

 int n,m;

 scanf("%d%d",&n,&m);

 for(int i=1;i<=n;i++) tree[i]=-1;

 while(m--){

     int a,b;

     scanf("%d%d",&a,&b);

     a=getRoot(a);b=getRoot(b);

     if(a!=b) tree[b]=a;

 }

 int count=0;

 for(int i=1;i<=n;i++){

     if(tree[i]==-1) count++;

 }

 printf("%d\n",count);

}

return 0;

}

71、 题目描述:

One way that the police finds the head of a gang is to check people's phone calls、 If there is a phone call between A and B, we say that A and B is related、 The weight of a relation is defined to be the total time length of all the phone calls made between the two persons、 A "Gang" is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threthold K、 In each gang, the one with maximum total weight is the head、 Now given a list of phone calls, you are supposed to find the gangs and the heads、

输入:

For each case, the first line contains two positive numbers N and K (both less than or equal to 1000), the number of phone calls and the weight threthold, respectively、 Then N lines follow, each in the following format:

Name1 Name2 Time

where Name1 and Name2 are the names of people at the two ends of the call, and Time is the length of the call、 A name is a string of three capital letters chosen from A-Z、 A time length is a positive integer which is no more than 1000 minutes、

输出:

For each test case, first print in a line the total number of gangs、 Then for each gang, print in a line the name of the head and the total number of the members、 It is guaranteed that the head is unique for each gang、 The output must be sorted according to the alphabetical order of the names of the heads、

样例输入:

8 59

AAA BBB 10

BBB AAA 20

AAA CCC 40

DDD EEE 5

EEE DDD 70

FFF GGG 30

GGG HHH 20

HHH FFF 10

8 70

AAA BBB 10

BBB AAA 20

AAA CCC 40

DDD EEE 5

EEE DDD 70

FFF GGG 30

GGG HHH 20

HHH FFF 10

样例输出:

2

AAA 3

GGG 3

0

#include <cstdio>

#include <cstring>

#include <vector>

#include <list>

#include <queue>

#include <algorithm>

using namespace std;

const int MAX_SIZE=1000+1;

//vector<int> edges[MAX_SIZE];

int cc[MAX_SIZE];

int cc_cnt;

const int MAX_NAME_LEN=3+1;

char name[MAX_SIZE][MAX_NAME_LEN];

int node_cnt;

int cc_weight[MAX_SIZE],max_node[MAX_SIZE],node_weight[MAX_SIZE];

class CompHeadName

{

public:

bool operator()(int n1,int n2)  {return strcmp(name[max_node[n1]],name[max_node[n2]])<0;}

};

int ufs_root(int n)

{

//while(cc[n]>=0)    n=cc[n];

//return n;

if(cc[n]<0)  return n;

else    return cc[n]=ufs_root(cc[n]);//路径压缩

}

int main_union()

{

int n,m,k;

while(scanf("%d%d",&m,&k)>0)

{

 int i,j,t;

 n=MAX_SIZE;

 memset(cc,-1,n*sizeof(int));

 memset(cc_weight,0,n*sizeof(int));

 memset(max_node,-1,n*sizeof(int));

 memset(node_weight,0,n*sizeof(int));

 char sname[MAX_NAME_LEN],dname[MAX_NAME_LEN];

 node_cnt=0;

 int src,dst,weight;

 int rs,rd;

 for(i=0;i<m;i++)

 {

     scanf("%s%s%d",sname,dname,&weight);

     for(src=0;src<node_cnt;src++)

  if(strcmp(sname,name[src])==0)  break;

     if(src==node_cnt)   strcpy(name[node_cnt++],sname);

     for(dst=0;dst<node_cnt;dst++)

  if(strcmp(dname,name[dst])==0)  break;

     if(dst==node_cnt)   strcpy(name[node_cnt++],dname);

  

     node_weight[src]+=weight;

     node_weight[dst]+=weight;

  

     rs=ufs_root(src);

     rd=ufs_root(dst);

     if(rs!=rd)

     {

  if(cc[rs]>=cc[rd])

  {

      t=rd;

      rd=rs;

      rs=t;

  }

  cc[rs]+=cc[rd];

  cc[rd]=rs;

  cc_weight[rs]+=cc_weight[rd];

  if(max_node[rs]<0 || node_weight[max_node[rd]]>node_weight[max_node[rs]]) max_node[rs]=max_node[rd];

     }

     cc_weight[rs]+=weight;

     if(max_node[rs]<0 || node_weight[src]>node_weight[max_node[rs]])  max_node[rs]=src;

     if(node_weight[dst]>node_weight[max_node[rs]])   max_node[rs]=dst;

 }

 int gang_cnt=0;

 int gangs[MAX_SIZE];

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

 {

     if(cc[i]>=0) continue;

     if(-cc[i]>2 && cc_weight[i]>k)    gangs[gang_cnt++]=i;

 }

 sort(gangs,gangs+gang_cnt,CompHeadName());

 printf("%d\n",gang_cnt);

 for(i=0;i<gang_cnt;i++)

 {

     printf("%s %d\n",name[max_node[gangs[i]]],-cc[gangs[i]]);

 }

}

return 0;

}

int main()

{

//main_bfs();

//main_dfs();

main_union();

return 0;

}

72、 题目描述:

某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离。省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不1定有直接的公路相连,只要能间接通过公路可达即可),并要求铺设的公路总长度为最小。请计算最小的公路总长度。

输入:

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( < 100 );随后的N(N-1)/2行对应村庄间的距离,每行给出1对正整数,分别是两个村庄的编号,以及此两村庄间的距离。为简单起见,村庄从1到N编号。

当N为0时,输入结束,该用例不被处理。

输出:

对每个测试用例,在1行里输出最小的公路总长度。

样例输入:

3

1 2 1

1 3 2

2 3 4

4

1 2 1

1 3 4

1 4 1

2 3 3

2 4 2

3 4 5

0

样例输出:

3

5

#include <stdio、h>

#include <stdlib、h>

#include <string、h>

#define N 100

#define MAX 1000000

typedef struct{

 int fromvex,endvex;

 int length;

}edge;

int dist[N][N];

void prim(int n){

 edge T[n - 1];

 int i,k,min,j,m,v,d;

 int sum = 0;

 edge e;

 for(i = 1;i < n;i ++){

  T[i - 1]、fromvex = 1;

  T[i - 1]、endvex = i + 1;

  T[i - 1]、length = dist[0][i];

 }

 for(k = 0;k < n-1;k ++){

  min = MAX;

  for(j = k;j < n -1;j ++){

   if(T[j]、length < min){

    min = T[j]、length;

    m = j;

   }

  }

  sum += T[m]、length;

  e = T[m];

  T[m] = T[k];

  T[k] = e;

  v = T[k]、endvex;

  for(j = k + 1;j < n-1;j ++){

   d  = dist[v - 1][T[j]、endvex- 1];

   if(d < T[j]、length){

    T[j]、length = d;

    T[j]、fromvex = v;

   }

  }

 }

 printf("%d\n",sum);

}

int main(){

 int n,i;

 int from,end,value;

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

  if(n == 0)  return 0;

  memset(dist,MAX,n * n * sizeof (int));

  int num = n *(n - 1)/2;

  for(i = 0;i < num;i ++){

   scanf("%d %d %d",&from,&end,&value);

   dist[from - 1][end - 1] = value;

   dist[end - 1][from - 1] = value;

  }

  prim(n);

 }

}

73、 题目描述:

In an episode of the Dick Van Dyke show, little Richie connects the freckles on his Dad's back to form a picture of the Liberty Bell、 Alas, one of the freckles turns out to be a scar, so his Ripley's engagement falls through、

Consider Dick's back to be a plane with freckles at various (x,y) locations、 Your job is to tell Richie how to connect the dots so as to minimize the amount of ink used、 Richie connects the dots by drawing straight lines between pairs, possibly lifting the pen between lines、 When Richie is done there must be a sequence of connected lines from any freckle to any other freckle、

输入:

The first line contains 0 < n <= 100, the number of freckles on Dick's back、 For each freckle, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the freckle、

输出:

Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the freckles、

样例输入:

3

1、0 1、0

2、0 2、0

2、0 4、0

样例输出:

3、41

#include<stdio、h>

#include<string、h>

#include<math、h>

#define INF 0x7fffffff

double dis[101][101],sum,x[101],y[101];

int flag[101]={0};

int visitedcount();

double prim();

int i,j,n,count,newx,newy,dist;

int main()

{

 //freopen("input、txt","r",stdin);

 while(~scanf("%d",&n)&&n!=0)

 {

  memset(dis,0,sizeof(dis));    //要加string、h头文件

  memset(flag,0,sizeof(flag));

  for(i=1;i<=n;i++)

   scanf("%lf %lf",&x[i],&y[i]);

  for(i=1;i<=n;i++)

   for(j=i+1;j<=n;j++)

   {

    dis[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));

    dis[j][i]=dis[i][j];

   }

  double out=prim();

  printf("%、2f\n",out);

 }

 return 0;

}

double prim()    //prim算法构造最小生成树

{

 flag[1]=1;

 sum=0;

 while(visitedcount()<n)

 {

  double min=INF;

  for(i=1;i<=n;i++)

  {

   if(flag[i]==1)

   {

    for(j=1;j<=n;j++)

    {

     if(flag[j]==0)

     {

      if(dis[i][j]<min)

      {

       min=dis[i][j];

       newx=i;

       newy=j;

      }

     }

    }

   }

  }

  flag[newy]=1;

  sum+=dis[newx][newy]; 

 }

 return sum;

}

int visitedcount()     //已包含顶点个数

{

 count=0;

 for(i=1;i<=n;i++)

  if(flag[i]==1)

   count++;

 return count;

}

74、 题目描述:

The Head Elder of the tropical island of Lagrishan has a problem、 A burst of foreign aid money was spent on extra roads between villages some years ago、 But the jungle overtakes roads relentlessly, so the large road network is too expensive to maintain、 The Council of Elders must choose to stop maintaining some roads、 The map above on the left shows all the roads in use now and the cost in aacms per month to maintain them、 Of course there needs to be some way to get between all the villages on maintained roads, even if the route is not as short as before、 The Chief Elder would like to tell the Council of Elders what would be the smallest amount they could spend in aacms per month to maintain roads that would connect all the villages、 The villages are labeled A through I in the maps above、 The map on the right shows the roads that could be maintained most cheaply, for 216 aacms per month、 Your task is to write a program that will solve such problems、

输入:

The input consists of one to 100 data sets, followed by a final line containing only 0、 Each data set starts with a line containing only a number n, which is the number of villages, 1 < n < 27, and the villages are labeled with the first n letters of the alphabet, capitalized、 Each data set is completed with n-1 lines that start with village labels in alphabetical order、 There is no line for the last village、 Each line for a village starts with the village label followed by a number, k, of roads from this village to villages with labels later in the alphabet、 If k is greater than 0, the line continues with data for each of the k roads、 The data for each road is the village label for the other end of the road followed by the monthly maintenance cost in aacms for the road、 Maintenance costs will be positive integers less than 100、 All data fields in the row are separated by single blanks、 The road network will always allow travel between all the villages、 The network will never have more than 75 roads、 No village will have more than 15 roads going to other villages (before or after in the alphabet)、 In the sample input below, the first data set goes with the map above、

输出:

The output is one integer per line for each data set: the minimum cost in aacms per month to maintain a road system that connect all the villages、 Caution: A brute force solution that examines every possible set of roads will not finish within the one minute time limit、

样例输入:

9

A 2 B 12 I 25

B 3 C 10 H 40 I 8

C 2 D 18 G 55

D 1 E 44

E 2 F 60 G 38

F 0

G 1 H 35

H 1 I 35

3

A 2 B 10 C 40

B 1 C 20

0

样例输出:

216

30

#include <iostream>

#include <vector>

#include <cstdio>

#include <algorithm>

#include <map>

using namespace std;

struct edge{

char x;

char y;

int cost;

edge(char a,char b,int c){

 x = a; y = b; cost = c;

}

};

map<char,char> fa;

vector<char> V;

vector<edge> E;

edge *p;

char find(char x){

if(x!=fa[x]) x = find(fa[x]);

return fa[x];

}

bool comp(edge a,edge b){

return a、cost<b、cost;

}

int main(int argc,char* argv[]){

//freopen("input、txt","r",stdin);

int N;

while(cin>>N&&N){

 V、clear();

 E、clear();

 char a,b;

 int n,c;

 N--;

 while(N--){

     cin>>a>>n;

     V、push_back(a);

     while(n--){

  cin>>b>>c;

  p = new edge(a,b,c);

  E、push_back(*p);

     }

 }

 for(int i=0;i<V、size();i++){

     fa[V[i]] = V[i];

 }

 int cost = 0;

 sort(E、begin(),E、end(),comp);

 for(int i=0;i<E、size();i++){

     //cout<<E[i]、x<<" "<<E[i]、y<<" "<<E[i]、cost<<endl;

     char fx,fy;

     fx = find(E[i]、x);

     fy = find(E[i]、y);

     if(fx<fy){

  fa[fy] = fx;

  cost += E[i]、cost;

     }

     else if(fx>fy){

  fa[fx] = fy;

  cost += E[i]、cost;

     }

 }

 cout<<cost<<endl;

}

return 0;

}

75、 题目描述:

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不1定有直接的公路相连,只要能间接通过公路可达即可)。经过调查评估,得到的统计表中列出了有可能建设公路的若干条道路的成本。现请你编写程序,计算出全省畅通需要的最低成本。

输入:

测试输入包含若干测试用例。每个测试用例的第1行给出评估的道路条数 N、村庄数目M (N, M < =100 );随后的 N 行对应村庄间道路的成本,每行给出1对正整数,分别是两个村庄的编号,以及此两村庄间道路的成本(也是正整数)。为简单起见,村庄从1到M编号。当N为0时,全部输入结束,相应的结果不要输出。

输出:

对每个测试用例,在1行里输出全省畅通需要的最低成本。若统计数据不足以保证畅通,则输出“?”。

样例输入:

3 3

1 2 1

1 3 2

2 3 4

1 3

2 3 2

0 100

样例输出:

3

?

#include<iostream>

#include<algorithm>

#include<memory、h>

using namespace std;

int N,M,father[110];

struct E{ 

  int a,b,v;

}e[110];

bool cmp(const E& A,const E& B){ return A、v<B、v;}

int find(int x){ return father[x]==-1 ? x : find(father[x]); }

bool Union(int x,int y){

  x=find(x); y=find(y);

  if(x==y) return false;

  else return father[y]=x;

}

void Kruskal(){

  int sum=0;

  for(int i=0;i<N;++i)

    if(Union(e[i]、a,e[i]、b) && M--) 

  sum+=e[i]、v;

   

  if(M<=1) cout<<sum<<endl;

  else cout<<"?"<<endl;

}

int  main(){

  while(cin>>N>>M && N!=0){

     memset(father,-1,sizeof(father));

     for(int i=0;i<N;++i)

    cin>>e[i]、a>>e[i]、b>>e[i]、v;

     sort(e,e+N,cmp);

     Kruskal();

  }

}

76题目描述:

省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不1定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。

输入:

测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。

当N为0时输入结束。

输出:

每个测试用例的输出占1行,输出全省畅通需要的最低成本。

样例输入:

3

1 2 1 0

1 3 2 0

2 3 4 0

3

1 2 1 0

1 3 2 0

2 3 4 1

3

1 2 1 0

1 3 2 1

2 3 4 1

0

样例输出:

3

1

0

#include <stdio、h>

#include <algorithm>

using namespace std;

#define MAX 5000

int father[101];

int w[MAX], u[MAX], v[MAX], r[MAX];

bool cmp(const int i, const int j) {return w[i]<w[j];}

int find(int x)

{

int fx, tx = x;

while(tx != father[tx]) { tx = father[tx];}

fx = tx;

while(x != father[x])

{

 tx = x;

 x = father[x];

 father[tx] = fx;

}

return x;

}

int main()

{

//freopen("JDOJ1028、IN", "r", stdin);

int n, flag;

while(scanf("%d", &n), n)

{

 int t = (n*(n-1))/2;

 for(int i=0; i<=n; i++) father[i] = i;

 for(int i=0; i<=t; i++) r[i] = i;

 for(int i=0; i<t; i++)

 {

     scanf("%d%d%d%d", &u[i], &v[i], &w[i], &flag);

     if(flag)

     {

  int fa = find(u[i]);

  int fb = find(v[i]);

  if(fa != fb)

  {

      if(i&1) father[fa] = fb;

      else father[fb] = fa;

  }

     }

 }

 sort(r, r+t, cmp);

 int sum = 0;

 for(int i=0; i<t; i++)

 {

     int e = r[i];

     int fu = find(u[e]);

     int fv = find(v[e]);

     if(fu != fv)

     {

  sum += w[e];

  if(i&1) father[fu] = fv;

  else father[fv] = fu;

     }

 }

 printf("%d\n", sum);

}//while(1);

return 0;

}

77、 题目描述:

在每年的校赛里,所有进入决赛的同学都会获得1件很漂亮的t-shirt。但是每当我们的工作人员将上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?

输入:

输入包括多组数据。每组数据第1行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有1条路,我们的工作人员需要C分钟的时间走过这条路。输入保证至少存在1条商店到赛场的路线。

当输入为两个0时,输入结束。

输出:

对于每组输入,输出1行,表示工作人员从商店走到赛场的最短时间。

样例输入:

2 1

1 2 3

3 3

1 2 5

2 3 5

3 1 2

0 0

样例输出:

3

2

#include <cstdio>

const short INF=10000;

int main()

{

//freopen("Main、txt", "r", stdin);

short n,m,a,b,c;

while(scanf("%hd %hd",&n,&m)==2)

{

 if(n==0&&m==0) break;

 short *g=new short[(n+1)*(n+1)];

 for(int i=0;i<n+1;++i)

     for(int j=0;j<n+1;++j)

     {

  if(i==j) *(g+i*(n+1)+j)=0;

  else *(g+i*(n+1)+j)=INF;

     }

 for(int i=0;i<m;++i)

 {

     scanf("%hd %hd %hd",&a,&b,&c);

     *(g+a*(n+1)+b)=c;

     *(g+b*(n+1)+a)=c;

 }

 short *set=new short[n+1];

 short *dist=new short[n+1];

 for(int i=0;i<n+1;++i) *(set+i)=0;

 dist[1]=0;

 set[1]=1;

 for(int j=2;j<n+1;++j) dist[j]=*(g+n+1+j);

 short minP;

 do

 {

     minP=-1;

     for(int i=1;i<n+1;i++)

     {

  if(set[i]==1) continue;

  if(minP==-1||dist[i]<dist[minP]) minP=i;

     }

     if(minP!=-1)

     {

  for(int i=1;i<n+1;++i)

  {

      if(set[i]==1) continue;

      if(*(g+minP*(n+1)+i)+dist[minP]<dist[i]) dist[i]=*(g+minP*(n+1)+i)+dist[minP];

  }

  //minP must greater than 0 or the heap memory will be corrupted

  set[minP] = 1;

     }

 }

 while(minP!=-1);

 printf("%hd\n",dist[n]);

 delete[] g;

 delete[] set;

 delete[] dist;

}

//fclose(stdin);

return 0;

}

78、 题目描述:

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入:

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有1条边,且其长度为d,花费为p。最后1行是两个数 s,t;起点s,终点t。n和m为0时输入结束。

(1<n<=1000, 0<m<100000, s != t)

输出:

输出 1行有两个数, 最短距离及其花费。

样例输入:

3 2

1 2 5 6

2 3 4 5

1 3

0 0

样例输出:

9 11

#include<iostream>

using namespace std;

const long MAX=1000;

const long BIAN=100000;

long map[MAX][MAX];

long Huafei[MAX][MAX];

long visit[MAX];

long path[MAX];

long Point;

int flag;

void Mappath(long G[][MAX],long GG[][MAX],long u,long v,long i,long &Minleng,long &Mincost)

{

  long j;

     if(path[i]==v)

     {

     long temp=0;

        for(j=0;j<=(i-1);j++)

      temp=temp+G[path[j]][path[j+1]];

     if(flag==0){flag++;Minleng=temp;}

     else

     {if(temp<Minleng)

     {

      Minleng=temp;

  

     }}

     }

     else

     {

     j=0;

        while(j<Point)

     {

     if(G[path[i]][j]!=(-1)&&visit[j]==0)

     {

     visit[j]=1;

     path[i+1]=j;

     Mappath(G,GG,u,v,i+1,Minleng,Mincost);

     visit[j]=0;

     }

     j++;

     }

    

     }

}

void XMappath(long G[][MAX],long GG[][MAX],long u,long v,long i,long &Minleng,long &Mincost)

{

  long j;

     if(path[i]==v)

     {

     long temp=0;

       for(j=0;j<=(i-1);j++)

    temp=temp+G[path[j]][path[j+1]];

     if(temp==Minleng)

     {

      temp=0;

     for(j=0;j<=(i-1);j++)

     temp=temp+GG[path[j]][path[j+1]];

     if(flag==0){flag++;Mincost=temp;}

     else {if(temp<Mincost)Mincost=temp;}

  

     }

     }

     else

     {

     j=0;

        while(j<Point)

     {

     if(G[path[i]][j]!=(-1)&&visit[j]==0)

     {

     visit[j]=1;

     path[i+1]=j;

     XMappath(G,GG,u,v,i+1,Minleng,Mincost);

     visit[j]=0;

     }

     j++;

     }

    

     }

}

int main()

{

   long n,m;

  //  FILE *stream;

  //  stream=freopen("1、txt","r",stdin);

    while(cin>>n>>m)

    {

    if(n==0&&m==0)break;

    long i,j;

    long juli,huafei;

    long k;

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

     for(j=0;j<n;j++)

     {

      map[i][j]=(-1);

     map[j][i]=(-1);

     Huafei[i][j]=(-1);

     Huafei[j][i]=(-1);

   

     }

    for(k=0;k<m;k++)

    {

    cin>>i>>j>>juli>>huafei;

    map[i-1][j-1]=juli;

    map[j-1][i-1]=juli;

    Huafei[i-1][j-1]=huafei;

    Huafei[j-1][i-1]=huafei;

    }

    long qidian,zongdian;

    cin>>qidian>>zongdian;

    qidian--;

    zongdian--;

   long zuiduanlujin;

   long zuishaohuafei;

    for(i=0;i<MAX;i++)visit[i]=0;

    path[0]=qidian;

    visit[qidian]=1;

    Point=n;

    flag=0;

   Mappath(map,Huafei,qidian,zongdian,0,zuiduanlujin,zuishaohuafei);

       for(i=0;i<MAX;i++)visit[i]=0;

    path[0]=qidian;

    visit[qidian]=1;

    Point=n;

   flag=0;

     XMappath(map,Huafei,qidian,zongdian,0,zuiduanlujin,zuishaohuafei);

   cout<<zuiduanlujin<<" "<<zuishaohuafei<<endl;

  

    }

return 0;

}

79、 题目描述:

N个城市,标号从0到N-1,M条道路,第K条道路(K从0开始)的长度为2^K,求编号为0的城市到其他城市的最短距离

输入:

第1行两个正整数N(2<=N<=100)M(M<=500),表示有N个城市,M条道路

接下来M行两个整数,表示相连的两个城市的编号

输出:

N-1行,表示0号城市到其他城市的最短路,如果无法到达,输出-1,数值太大的以MOD 100000 的结果输出。

样例输入:

4 4

1 2

2 3

1 3

0 1

样例输出:

8

9

11

#include<iostream>

#include<vector>

#include<cstdio>

#include<algorithm>

#include<string、h>

using namespace std;

int data[200][200];

vector<int>dis[200];

int s[200];

int n,m;

long long Pow(int n)

{

 if(n==1)

  return 2;

 else if(n==0)

  return 1;

 if((n&1)==1)

  return 2*Pow(n-1)%100000;

 else

 {

  long long t=Pow(n>>1)%100000;

  return t*t%100000;

 }

}

vector<int> operator +(vector<int>vec,int data)

{

 vector<int>temp;

 sort(vec、begin(),vec、end());

 vector<int>::iterator it=vec、begin();

 for(;it!=vec、end();it++)

 {

  if(*it==data)

  {

   *it++;

   temp=vec;

   return temp;

  }

 }

 temp=vec;

 temp、push_back(data);

 return temp;

}

bool operator < (vector<int> vec, vector<int>vec2)

{

 sort(vec、begin(),vec、end());

 sort(vec2、begin(),vec2、end());

 vector<int>::iterator it=vec、end(),it2=vec2、end();

 it--;

 it2--;

 while(it!=vec、begin()&& it2!=vec2、begin())

 {

  if(*it<*it2)

   return true;

  else if(*it>*it2)

   return false;

  else

  {

   it--;

   it2--;

  }

 }

 if(*it==*it2)

  return vec、size()<vec2、size();

 else

  return *it<*it2; 

}

int main()

{

 while(scanf("%d %d",&n,&m)!=EOF)

 {

  memset(data,-1,sizeof(data));

  int s1,s2;

  int k=0;

  for(int i=0;i<m;i++)

  {

   scanf("%d %d",&s1,&s2);

   data[s1][s2]=k;

   data[s2][s1]=k++;

  }

///

  memset(s,0,sizeof(s));

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

  {

   dis[i]、clear();

   dis[i]、push_back(1000);

  }

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

   if(data[0][i]!=-1)

   {

    dis[i]、clear();

    dis[i]、push_back(data[0][i]);

   }

  s[0]=1;

  int u=0;

  for(int i=1;i<n;i++)

  {

   vector<int>mindis;

   mindis、push_back(1000);

   for(int j=0;j<n;j++)

   {

    if(s[j]==0 && dis[j]<mindis)

    {

     u=j;

     mindis=dis[j];

    }

   }

   s[u]=1;

   for(int j=0;j<n;j++)

   {

    if(s[j]==0 && data[u][j]!=-1 &&

    dis[u]+data[u][j]<dis[j])

    {

     dis[j]=dis[u]+data[u][j];

    }

   }

  }

  for(int i=1;i<n;i++)

  {

   long long length=0;

   if(dis[i]、size()==1&&dis[i][0]==1000)

   {

    cout<<"-1"<<endl;

    continue;

   }

   for(int j=0;j<dis[i]、size();j++)

   {

    /*我擦,在这里纠结了好久,没有取余,白WA了N次*/

    length+=Pow(dis[i][j]);

    length%=100000;

   }

   cout<<length<<endl;

  }

 }

 return 0;

}

80、 题目描述:

The country is facing a terrible civil war----cities in the country are divided into two parts supporting different leaders、 As a merchant, Mr、 M does not pay attention to politics but he actually knows the severe situation, and your task is to help him reach home as soon as possible、

"For the sake of safety,", said Mr、M, "your route should contain at most 1 road which connects two cities of different camp、"

Would you please tell Mr、 M at least how long will it take to reach his sweet home?

输入:

The input contains multiple test cases、

The first line of each case is an integer N (2<=N<=600), representing the number of cities in the country、

The second line contains one integer M (0<=M<=10000), which is the number of roads、

The following M lines are the information of the roads、 Each line contains three integers A, B and T, which means the road between city A and city B will cost time T、 T is in the range of [1,500]、

Next part contains N integers, which are either 1 or 2、 The i-th integer shows the supporting leader of city i、

To simplify the problem, we assume that Mr、 M starts from city 1 and his target is city 2、 City 1 always supports leader 1 while city 2 is at the same side of leader 2、

Note that all roads are bidirectional and there is at most 1 road between two cities、

Input is ended with a case of N=0、

输出:

For each test case, output one integer representing the minimum time to reach home、

If it is impossible to reach home according to Mr、 M's demands, output -1 instead、

样例输入:

2

1

1 2 100

1 2

3

3

1 2 100

1 3 40

2 3 50

1 2 1

5

5

3 1 200

5 3 150

2 5 160

4 3 170

4 2 170

1 2 2 2 1

0

样例输出:

100

90

540

#include <stdio、h>

#include <vector>

using namespace std;

struct E{

 int next;

 int t;

};

vector <E> edge[610];

bool mark[610];

int time[610];

int owner[610];

int main(){

 int n,m;

 while(scanf("%d",&n)!=EOF && n!=0){

  scanf("%d",&m);

  for(int i=1;i<=n;i++){

   edge[i]、clear();

  }

  int a,b,t;

  for(int i=0;i<m;i++){

   scanf("%d%d%d",&a,&b,&t);

   E tmp;

   tmp、next=b;

   tmp、t=t;

   edge[a]、push_back(tmp);

   tmp、next=a;

   edge[b]、push_back(tmp);

  }

  for(int i=1;i<=n;i++){

   mark[i]=false;

   time[i]=-1;

   scanf("%d",&owner[i]);

  }

  for(int i=1;i<=n;i++){

   if(owner[i]==2){

    for(int j=0;j<edge[i]、size();j++){

     if(owner[edge[i][j]、next]==1){

      edge[i][j]、t=0;

     }

    }

   }

  }

  time[1]=0;

  mark[1]=true;

  int newp=1;

  for(int i=1;i<n;i++){

   for(int j=0;j<edge[newp]、size();j++){

    int next_=edge[newp][j]、next;

    int time_=edge[newp][j]、t;

    if(mark[next_]==true)

     continue;

    if(time_==0)

     continue;

    if(time[next_]==-1 || time[next_]>time[newp]+time_){

     time[next_]=time[newp]+time_;

    }

   }

    int min=1000;

    for(int j=1;j<=n;j++){

     if(mark[j]==true)

      continue;

     if(time[j]==-1)

      continue;

     if(time[j]<min){

      min=time[j];

      newp=j;

     }

    }

    mark[newp]=true;

   }

   if(time[2]!=-1)

    printf("%d\n",time[2]);

   else

    printf("-1\n");

 }

 return 0;

}

81、 题目描述:

ACM-DIY is a large QQ group where many excellent acmers get together、 It is so harmonious that just like a big family、 Every day,many "holy cows" like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas、 When someone has questions, many warm-hearted cows like Lost will come to help、 Then the one being helped will call Lost "master", and Lost will have a nice "prentice"、 By and by, there are many pairs of "master and prentice"、 But then problem occurs: there are too many masters and too many prentices, how can we know whether it is legal or not?We all know a master can have many prentices and a prentice may have a lot of masters too, it's legal、 Nevertheless,some cows are not so honest, they hold illegal relationship、 Take HH and 3xian for instant, HH is 3xian's master and, at the same time, 3xian is HH's master,which is quite illegal! To avoid this,please help us to judge whether their relationship is legal or not、 Please note that the "master and prentice" relation is transitive、 It means that if A is B's master ans B is C's master, then A is C's master、

输入:

The input consists of several test cases、 For each case, the first line contains two integers, N (members to be tested) and M (relationships to be tested)(2 <= N, M <= 100)、 Then M lines follow, each contains a pair of (x, y) which means x is y's master and y is x's prentice、 The input is terminated by N = 0、TO MAKE IT SIMPLE, we give every one a number (0, 1, 2,、、、, N-1)、 We use their numbers instead of their names、

输出:

For each test case, print in one line the judgement of the messy relationship、If it is legal, output "YES", otherwise "NO"、

样例输入:

3 2

0 1

1 2

2 2

0 1

1 0

0 0

样例输出:

YES

NO

#include <cstdio>

#include <queue>

using namespace std;

struct relation

{

short a;

short b;

};

short findStart(relation *r,short n,short m,short mark[])

{

bool find = false;

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

{

 if(mark[i]==0) continue;

 find = false;

 for(short j=0;j<m;++j)

 {

     if((r+j) >a==0&&(r+j) >b==0) continue;

     if((r+j) >b==i)

     {

  find = true;

  break;

     }

 }

 if(!find) return i;

}

return -1;

}

short deleteX(relation *r,short x,short m,short mark[])

{

if(x>-1)

{

 mark[x]=0;

 for(int i=0;i<m;++i)

 {

     if((r+i) >a==x)

     {

  (r+i) >a=0;

  (r+i) >b=0;

     }

 }

}

return x;

}

int main()

{

//freopen("Main、txt", "r", stdin);

short n,m;

while(scanf("%hd %hd",&n,&m)==2)

{

 if(n==0) break;

 relation *r = new relation[m];

 for(int i=0;i<m;++i) scanf("%hd %hd",&((r+i) >a),&((r+i) >b));

 short *mark=new short[n];

 for(int i=0;i<n;++i) mark[i]=1;

 while(deleteX(r,findStart(r,n,m,mark),m,mark)>-1);

 bool yes = true;

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

     if(mark[i]==1)

     {

  yes = false;

  break;

     }

 if(yes) printf("YES\n");

 else printf("NO\n");

 delete[] r;

 delete[] mark;

}

//fclose(stdin);

return 0;

}

82、 题目描述:

有N个比赛队(1<=N<=500),编号依次为1,2,3,。。。。,N进行比赛,比赛结束后,裁判委员会要将所有参赛队伍从前往后依次排名,但现在裁判委员会不能直接获得每个队的比赛成绩,只知道每场比赛的结果,即P1赢P2,用P1,P2表示,排名时P1在P2之前。现在请你编程序确定排名。

输入:

输入有若干组,每组中的第1行为二个数N(1<=N<=500),M;其中N表示队伍的个数,M表示接着有M行的输入数据。接下来的M行数据中,每行也有两个整数P1,P2表示即P1队赢了P2队。

输出:

给出1个符合要求的排名。输出时队伍号之间有空格,最后1名后面没有空格。

其他说明:符合条件的排名可能不是唯1的,此时要求输出时编号小的队伍在前;输入数据保证是正确的,即输入数据确保1定能有1个符合要求的排名。

样例输入:

4 3

1 2

2 3

4 3

样例输出:

1 2 4 3

#include <cstdio>

struct r

{

short p1,p2;

};

short find(short *mark,r *rs,short n,short m)

{

bool f=false;

for(int i=1;i<=n;++i)

{

 if(!mark[i]) continue;

 f=false;

 for(int j=0;j<m;++j)

 {

     if((rs+j) >p2==i)

     {

  f=true;

  break;

     }

 }

 if(!f) return i;

}

return -1;

}

short deleteX(short x,short *mark,r *rs,short n,short m)

{

if(x>-1)

{

 mark[x]=0;

 for(int i=0;i<m;++i)

 {

     if((rs+i) >p1==x)

     {

  (rs+i) >p1=-1;

  (rs+i) >p2=-1;

     }

 }

}

return x;

}

int main()

{

short n,m;

while(scanf("%hd %hd",&n,&m)==2)

{

 r *rs = new r[m];

 short *mark=new short[n+1],*result = new short[n+1],resultLen=0;

 for(int i=0;i<n+1;++i) mark[i]=1;

 for(int i=0;i<m;++i) scanf("%hd %hd",&(rs+i) >p1,&(rs+i) >p2);

 while((result[resultLen++]=deleteX(find(mark,rs,n,m),mark,rs,n,m))>-1);

 printf("%hd",result[0]);

 for(int i=1;i<resultLen-1;++i) printf(" %hd",result[i]);

 putchar('\n');

 delete[] rs;

 delete[] mark;

 delete[] result;

}

return 0;

}

83、 题目描述:

有1群人,打乒乓球比赛,两两捉对撕杀,每两个人之间最多打1场比赛。

球赛的要求如下:

如果A打败了B,B又打败了C,而A与C之间没有进行过比赛,那么就认定,A1定能打败C。

如果A打败了B,B又打败了C,而且,C又打败了A,那么A、B、C三者都不可能成为冠军。

根据这个要求,无需循环较量,或许就能确定冠军。你的任务就是面对1群比赛选手,在经过了若干场撕杀之后,确定是否已经实际上产生了冠军。

输入:

输入含有1些选手群,每群选手都以1个整数n(n<1000)开头,后跟n对选手的比赛结果,比赛结果以1对选手名字(中间隔1空格)表示,前者战胜后者。如果n为0,则表示输入结束。

输出:

对于每个选手群,若你判断出产生了冠军,则在1行中输出“Yes”,否则在1行中输出“No”。

样例输入:

3

Alice Bob

Smith John

Alice Smith

5

a c

c d

d e

b e

a d

0

样例输出:

Yes

No

#include<stdio、h>

#include<string、h>

#include<string>

#include<map>

using namespace std;

map<string,int> M;

int data[2002];

int main(){

char str1[101],str2[101];

int n;

while(scanf("%d",&n)&&n!=0){

 M、clear();

 int size=0;

 for(int i=0;i<n*2;i++)data[i]=0;

 while(n--){

   scanf("%s%s",str1,str2);

   string a=str1,b=str2;

   int sib;

   if(M、find(a)==M、end())M[a]=size++;

   if(M、find(b)==M、end()){

   sib=size;

   M[b]=size++;

   }

   else sib=M[b];

   data[sib]++;

 }

 int num=0;

 for(int i=0;i<size;i++)

  if(data[i]==0)num++;

 puts(num==1?"Yes":"No");

}

return 0;

}

84、 题目描述:

用小于等于n元去买100只鸡,大鸡5元/只,小鸡3元/只,还有1/3元每只的1种小鸡,分别记为x只,y只,z只。编程求解x,y,z所有可能解。

输入:

测试数据有多组,输入n。

输出:

对于每组输入,请输出x,y,z所有可行解,按照x,y,z依次增大的顺序输出。

样例输入:

40

样例输出:

x=0,y=0,z=100

x=0,y=1,z=99

x=0,y=2,z=98

x=1,y=0,z=99

#include <iostream>

#include <cstdio>

using namespace std;

int N;

int main()

{

 while(cin>>N)

 {

  for(int i = 0; i<=100; i++)

   for(int j = 0; j<=100; j++)

   {

    int sum = 14*i+8*j;

    if(sum<=3*N-100)

    {

     printf("x=%d,y=%d,z=%d\n",i,j,100-i-j);

    }

   }

 }

 return 0;

}

85、 题目描述:

设a、b、c均是0到9之间的数字,abc、bcc是两个三位数,且有:abc+bcc=532。求满足条件的所有a、b、c的值。

输入:

题目没有任何输入。

输出:

请输出所有满足题目条件的a、b、c的值。

a、b、c之间用空格隔开。

每个输出占1行。

样例输入:

样例输出:

#include<iostream>

using namespace std;

int main()

{

 int a,b,c;

 for(a=1;a<5;a++)

  for(b=1;b<5;b++)

   for(c=0;c<=9;c++)

 if((a*100+b*10+c+b*100+c*10+c)==532)

  cout<<a<<" "<<b<<" "<<c<<endl;

 return 0;

}

86、 题目描述:

输入10个数,要求输出其中的最大值。

输入:

测试数据有多组,每组10个数。

输出:

对于每组输入,请输出其最大值(有回车)。

样例输入:

10 22 23 152 65 79 85 96 32 1

样例输出:

max=152

#include <iostream>

using namespace std;

int main()

{

 int max = -1;

 int i = 0;

 int tmp;

 while(cin>>tmp)

 {

  if(max <tmp)

  {

   max = tmp;

  }

  if(0 == ++i%10)

  {

   cout << "max=" << max << endl;

   max = -1;

  }

  

 }

 return 0;

}

87、 题目描述:

Ignatius被魔王抓走了,有1天魔王出差去了,这可是Ignatius逃亡的好机会、魔王住在1个城堡里,城堡是1个A*B*C的立方体,可以被表示成A个B*C的矩阵,刚开始Ignatius被关在(0,0,0)的位置,离开城堡的门在(A-1,B-1,C-1)的位置,现在知道魔王将在T分钟后回到城堡,Ignatius每分钟能从1个坐标走到相邻的六个坐标中的其中1个、现在给你城堡的地图,请你计算出Ignatius能否在魔王回来前离开城堡(只要走到出口就算离开城堡,如果走到出口的时候魔王刚好回来也算逃亡成功),如果可以请输出需要多少分钟才能离开,如果不能则输出-1、

输入:

输入数据的第1行是1个正整数K,表明测试数据的数量、每组测试数据的第1行是四个正整数A,B,C和T(1<=A,B,C<=50,1<=T<=1000),它们分别代表城堡的大小和魔王回来的时间、然后是A块输入数据(先是第0块,然后是第1块,第2块、、、、、、),每块输入数据有B行,每行有C个正整数,代表迷宫的布局,其中0代表路,1代表墙。

输出:

对于每组测试数据,如果Ignatius能够在魔王回来前离开城堡,那么请输出他最少需要多少分钟,否则输出-1、

样例输入:

1

3 3 4 20

0 1 1 1

0 0 1 1

0 1 1 1

1 1 1 1

1 0 0 1

0 1 1 1

0 0 0 0

0 1 1 0

0 1 1 0

样例输出:

11

#include <stdio、h>

#include <queue>

using std::queue;

const short MAX = 50;

short k, a, b, c, t;

short map[MAX][MAX][MAX];

struct State {

short x, y, z, t;

};

struct Move {

short dx, dy, dz;

};

Move movs[6]={

{0, 0, 1},

{0, 0, -1},

{1, 0, 0},

{0, 1, 0},

{-1, 0, 0},

{0, -1, 0}

};

short bfs(State s) {

State newState, currentState;

queue<State> q;

q、push(s);

map[s、z][s、x][s、y] = 1;

while (!q、empty()) {

 currentState = q、front(); q、pop();

 if (currentState、x == b-1 &&

     currentState、y == c-1 &&

     currentState、z == a-1) {

     return currentState、t;

 }

 for (short i=0; i < 6; ++i) {

     newState、x = currentState、x + movs[i]、dx;

     newState、y = currentState、y + movs[i]、dy;

     newState、z = currentState、z + movs[i]、dz;

     newState、t = currentState、t + 1;

     if (newState、x < 0 || newState、x >= b ||

  newState、y < 0 || newState、y >= c ||

  newState、z < 0 || newState、z >= a) continue;

     if (map[newState、z][newState、x][newState、y] == 1) continue;

     q、push(newState);

     map[newState、z][newState、x][newState、y] = 1;

 }

}

return -1;

}

int main() {

scanf("%hd", &k);

for (short i=0; i < k; ++i) {

 scanf("%hd %hd %hd %hd", &a, &b, &c, &t);

 for (short i=0; i < a; ++i) {

     for (short j=0; j < b; ++j) {

  for (short k=0; k < c; ++k) {

      scanf("%hd", &map[i][j][k]);

  }

     }

 }

 State s = {0, 0, 0, 0};

 short result = 0;

 printf("%hd\n", (result = bfs(s)) <= t?result:-1);

}

return 0;

}

88、 题目描述:

大家1定觉的运动以后喝可乐是1件很惬意的事情,但是seeyou却不这么认为。因为每次当seeyou买了可乐以后,阿牛就要求和seeyou1起分享这1瓶可乐,而且1定要喝的和seeyou1样多。但seeyou的手中只有两个杯子,它们的容量分别是N 毫升和M 毫升 可乐的体积为S (S<101)毫升(正好装满1瓶) ,它们三个之间可以相互倒可乐 (都是没有刻度的,且 S==N+M,101>S>0,N>0,M>0) 。聪明的ACMER你们说他们能平分吗?如果能请输出倒可乐的最少的次数,如果不能输出"NO"。

输入:

三个整数 : S 可乐的体积 , N 和 M是两个杯子的容量,以"0 0 0"结束。

输出:

如果能平分的话请输出最少要倒的次数,否则输出"NO"。

样例输入:

7 4 3

4 1 3

0 0 0

样例输出:

NO

3

#include <cstdio>

#include <queue>

using std::queue;

const short MAX = 101;

short N, M ,S;

bool map[MAX][MAX];

struct State {

short n, m, s, t;

};

void poura2b(short &a, short &b, short aMax, short bMax) {

//need a temporary variable to hold the original value of b

short bOld = b;

b = b + a;

if (b > bMax) b = bMax;

a = a - (b - bOld);

if (a < 0) a = 0;

}

short solve(short n, short m, short s) {

queue<State> q;

State cur = {n, m , s, 0}, news;

q、push(cur);

while (!q、empty()) {

 cur = q、front(); q、pop();

 if (cur、n + cur、m == cur、s) return cur、t;

 news = cur;

 poura2b(news、n, news、m, N, M); news、t++;

 if (map[news、n][news、m] == false) {

     q、push(news);

     map[news、n][news、m] = true;

 }

 news = cur;

 poura2b(news、m, news、n, M, N); news、t++;

 if (map[news、n][news、m] == false) {

     q、push(news);

     map[news、n][news、m] = true;

 }

 news = cur;

 poura2b(news、n, news、s, N, S); news、t++;

 if (map[news、n][news、m] == false) {

     q、push(news);

     map[news、n][news、m] = true;

 }

 news = cur;

 poura2b(news、s, news、n, S, N); news、t++;

 if (map[news、n][news、m] == false) {

     q、push(news);

     map[news、n][news、m] = true;

 }

 news = cur;

 poura2b(news、m, news、s, M, S); news、t++;

 if (map[news、n][news、m] == false) {

     q、push(news);

     map[news、n][news、m] = true;

 }

 news = cur;

 poura2b(news、s, news、m, S, M); news、t++;

 if (map[news、n][news、m] == false) {

     q、push(news);

     map[news、n][news、m] = true;

 }

}

return -1;

}

int main() {

while (scanf("%hd %hd %hd", &S, &N, &M) == 3) {

 if (N == 0 && S == 0 && M == 0) break;

 if (S&1) {

     puts("NO");

     continue;

 }

 for (int i = 0; i < MAX; ++i)

     for (int j = 0; j < MAX; ++j)

  map[i][j] = false;

 map[0][0] = true;

 short r = solve(0, 0, S);

 if (r == -1) printf("NO\n");

 else

     printf("%hd\n", r);

}

return 0;

}

89、 题目描述:

约19世纪末,在欧州的商店中出售1种智力玩具,在1块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是1次只能移动1个盘,且不允许大盘放在小盘的上面。现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动1定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能将这些圆盘从最左边移到最右边?

输入:

包含多组数据,每次输入1个N值(1<=N=35)。

输出:

对于每组数据,输出移动最小的次数。

样例输入:

1

3

12

样例输出:

2

26

531440

#include<stdio、h>

long long F(int n)

{

if(n==1) return 2;

else

 return 3*F(n-1)+2;

}

int main()

{

int n;

while(scanf("%d",&n)!=EOF)

{

 printf("%lld\n",F(n));

}

return 0;

}

90、 题目描述:

A ring is compose of n circles as shown in diagram、 Put natural number 1, 2, 、、、, n into each circle separately, and the sum of numbers in two adjacent circles should be a prime、

Note: the number of first circle should always be 1、

输入:

n (1 < n < 17)、

输出:

The output format is shown as sample below、 Each row represents a series of circle numbers in the ring beginning from 1 clockwisely and anticlockwisely、 The order of numbers must satisfy the above requirements、 Print solutions in lexicographical order、

You are to write a program that completes above process、

Print a blank line after each case、

样例输入:

6

8

样例输出:

Case 1:

1 4 3 2 5 6

1 6 5 2 3 4

Case 2:

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

#include<iostream>

#include<cstdio>

#include<limits、h>

#include<memory、h>

#include<queue>

#include<string>

#include<vector>

using namespace std;

bool prime[100],mark[20];

int n,ans[50];

void p()

{

int i,j,k;

memset(prime,0,100*sizeof(bool));

for(i=2;i<100;i++)

{

 if(!prime[i])

 {

     for(j=i;i*j<100;j++)

  prime[i*j]=true;

 }

}

}

void init()

{

memset(mark,0,sizeof(mark));

}

void print()

{

printf("1");

for(int i=2;i<=n;i++)

 printf(" %d",ans[i]);

printf("\n");

}

void print(int j)

{

printf("1");

for(int i=2;i<=j;i++)

 printf(" %d",ans[i]);

printf("\n");

}

void dfs(int i)

{

//cout<<i<<"   begin"<<endl;

if(i==n&&!prime[ans[1]+ans[n]])

{

 print();

 return ;

}

for(int j=2;j<=n;j++)

{

 if(i==5)

 {

     for(int k=2;k<=6;k++)

     {

  if(!mark[k])

  {

  //  cout<<k<<" unvsed "<<endl;

  //  cout<<ans[i]<<" "<<ans[i]+k<<endl;

      ;

  }

     }

  

 }

 if(!mark[j]&&!prime[ans[i]+j])

 {

     //cout<<ans[i]<<" "<<j<<"  ";

     mark[j]=true;

     ans[i+1]=j;

     dfs(i+1);

     mark[j]=false;

 }

}

//  print(i+1);

//  cout<<i<<"   end"<<endl;

}

int main()

{

int i,j,k,cnt=1;

char temp[101];

//freopen("F:\\test、txt","r",stdin);

p();

ans[1]=1;

while(scanf("%d",&n)!=EOF)

{

 init();

 printf("Case %d:\n",cnt++);

 dfs(1);

 printf("\n");

}

return 0;

}

91、 题目描述:

The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits、 GeoSurvComp works with one large rectangular region of land at a time, and creates a grid that divides the land into numerous square plots、 It then analyzes each plot separately, using sensing equipment to determine whether or not the plot contains oil、 A plot containing oil is called a pocket、 If two pockets are adjacent, then they are part of the same oil deposit、 Oil deposits can be quite large and may contain numerous pockets、 Your job is to determine how many different oil deposits are contained in a grid、

输入:

The input file contains one or more grids、 Each grid begins with a line containing m and n, the number of rows and columns in the grid, separated by a single space、 If m = 0 it signals the end of the input; otherwise 1 <= m <= 100 and 1 <= n <= 100、 Following this are m lines of n characters each (not counting the end-of-line characters)、 Each character corresponds to one plot, and is either `*', representing the absence of oil, or `@', representing an oil pocket、

输出:

For each grid, output the number of distinct oil deposits、 Two different pockets are part of the same oil deposit if they are adjacent horizontally, vertically, or diagonally、 An oil deposit will not contain more than 100 pockets、

样例输入:

1 1

*

3 5

*@*@*

**@**

*@*@*

1 8

@@****@*

5 5

****@

*@@*@

*@**@

@@@*@

@@**@

0 0

样例输出:

0

1

2

2

#include<stdio、h>

#define N 101

char oil[N][N];

//bool mark[N][N];

int go[][2]={0,1,0,-1,1,0,-1,0,

1,1,1,-1,-1,1,-1,-1};

int m,n;

void make(int x,int y){

//if(oil[x][y]!='@' || mark[x][y]==true)return;

oil[x][y]='*';

for(int i=0;i<8;i++){

 int a=x+go[i][0];

 int b=y+go[i][1];

 if(a<0||a>=m||b<0||b>=n)continue;

 if(oil[a][b]=='@'){

     //oil[a][b]='*';

     make(a,b);

 }

}

}

int main(){

int sum,i,j;

while(1){

 sum=0;

 scanf("%d%d",&m,&n);

 if(m==0 && n==0)break;

 for(int i=0;i<m;i++){

     scanf("%s",oil[i]);

 }

 for(i=0;i<m;i++){

     for(j=0;j<n;j++){

  if(oil[i][j]=='@'){

      sum++;

      make(i,j);

  }

     }

 }

 printf("%d\n",sum);

}

}

92、 题目描述:

给定1个由不同的小写字母组成的string,输出这个string的所有全排列。

我们假设对于小写字母有'a' < 'b' < 、、、 < 'y' < 'z',而且给定的string中的字母已经按照从小到大的顺序排列。

输入:

输入只有1行,是1个由不同的小写字母组成的string,已知string的长度在1到6之间。

输出:

输出这个string的所有排列方式,每行1个排列。要求字母序比较小的排列在前面。字母序如下定义:

已知S = s1s2、、、sk , T = t1t2、、、tk,则S < T 等价于,存在p (1 <= p <= k),使得

s1 = t1, s2 = t2, 、、、, sp - 1 = tp - 1, sp < tp成立。

样例输入:

abc

样例输出:

abc

acb

bac

bca

cab

cba

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int main()

{

char str[7];

while(scanf("%s", str) != EOF)

{

int len = strlen(str);

do

{

printf("%s\n", str);

}

while(next_permutation(str, str + len));

printf("\n");

}

return 0;

}

93、 题目描述:

The doggie found a bone in an ancient maze, which fascinated him a lot、 However, when he picked it up, the maze began to shake, and the doggie could feel the ground sinking、 He realized that the bone was a trap, and he tried desperately to get out of this maze、

The maze was a rectangle with sizes N by M、 There was a door in the maze、 At the beginning, the door was closed and it would open at the T-th second for a short period of time (less than 1 second)、 Therefore the doggie had to arrive at the door on exactly the T-th second、 In every second, he could move one block to one of the upper, lower, left and right neighboring blocks、 Once he entered a block, the ground of this block would start to sink and disappear in the next second、 He could not stay at one block for more than one second, nor could he move into a visited block、 Can the poor doggie survive? Please help him、

输入:

The input consists of multiple test cases、 The first line of each test case contains three integers N, M, and T (1 < N, M < 7; 0 < T < 50), which denote the sizes of the maze and the time at which the door will open, respectively、 The next N lines give the maze layout, with each line containing M characters、 A character is one of the following:

'X': a block of wall, which the doggie cannot enter;

'S': the start point of the doggie;

'D': the Door; or

'、': an empty block、

The input is terminated with three 0's、 This test case is not to be processed、

输出:

For each test case, print in one line "YES" if the doggie can survive, or "NO" otherwise、

样例输入:

4 4 5

S、X、

、、X、

、、XD

、、、、

3 4 5

S、X、

、、X、

、、、D

0 0 0

样例输出:

NO

YES

#include<stdio、h>

int N,M,T,s;

int go[][2]={0,1,0,-1,-1,0,1,0};

char maze[7][7];

bool DFS(int x,int y,int t){

s++;

maze[x][y]='X';

for(int i=0;i<4;i++){

 int a=x+go[i][0];

 int b=y+go[i][1];

 if(a<0||b<0||a>=N||b>=M)continue;

 if(maze[a][b]=='D'){

     if(t+1==T)return true;

     else continue;

 }

 if(maze[a][b]=='、'){

     if(DFS(a,b,t+1))return true;

 }

}

maze[x][y]='、';

s--;

return false;

}

int main(){

int i,j,sx,sy;

while(1){

 scanf("%d%d%d",&N,&M,&T);

 if(N==0 &&M==0&&T==0)break;

 for(i=0;i<N;i++){

     scanf("%s",maze[i]);

 }

 for(i=0;i<N;i++){

     for(j=0;j<M;j++){

  if(maze[i][j]=='S'){

      sx=i;

      sy=j;

  }

     }

 }

 s=0;

 //printf("%d,%d",sx,sy);

 if(DFS(sx,sy,0))puts("YES");

 else puts("NO");

}

return 0;

}

94、 题目描述:

N阶楼梯上楼问题:1次可以走两阶或1阶,问有多少种上楼方式。(要求采用非递归)

输入:

输入包括1个整数N,(1<=N<90)。

输出:

可能有多组测试数据,对于每组数据,

输出当楼梯阶数是N时的上楼方式个数。

样例输入:

4

样例输出:

5

#include <iostream>

using namespace std;

//将iArrayS中的元素复制都iArrayD中

void int_array_copy(int iArrayD[],int iArrayS[])

{

 for(int i = 0; i <= iArrayS[0]; ++i)

 {

  iArrayD[i] = iArrayS[i];

 }

}

//将两个数组的元素相加

void int_array_add(int iArrayA[],int iArrayB[],int iArrayC[])

{

 int c = 0; //进位

 int tmp;

 int i;

 iArrayC[0] = iArrayB[0];

 for(i = 1; i <= iArrayA[0]; ++i)

 {

  tmp = iArrayA[i] + iArrayB[i] + c;

  iArrayC[i] = tmp % 10;

  c = tmp / 10;

 }

 while(i <= iArrayB[0])

 {

  tmp = iArrayB[i] + c;

  iArrayC[i] = tmp % 10;

  c = tmp / 10;

  i++;

 }

 if(c)

 {

  iArrayC[i] = c;

  iArrayC[0]++;

 }

}

void Nfloor(int n)

{

 int A[30],B[30],C[30];

A[0] = 1;

 A[1] = 1;

 B[0] = 1;

B[1] = 2;

 if(n == 1)

  cout << "1" << endl;

 else if(n == 2)

  cout << "2" << endl;

 else

 {

  n -= 2;

  while(n--)

  {

   int_array_add(A,B,C);

   int_array_copy(A,B);

   int_array_copy(B,C);

  }

  for(int i = C[0]; i >1; --i)

  {

   cout <<C[i];

  }

  cout << C[1] << endl;

 }

}

int main()

{

 int N;

 while(cin >> N)

 {

  Nfloor(N);

 }

 return 0;

}

95、 题目描述:

大家常常感慨,要做好1件事情真的不容易,确实,失败比成功容易多了!

做好“1件”事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是比挣钱容易的道理1样。

话虽这样说,我还是要告诉大家,要想失败到1定程度也是不容易的。比如,我高中的时候,就有1个神奇的女生,在英语考试的时候,竟然将40个单项选择题全部做错了!大家都学过概率论,应该知道出现这种情况的概率,所以至今我都觉得这是1件神奇的事情。如果套用1句经典的评语,我们可以这样总结:1个人做错1道选择题并不难,难的是全部做错,1个不对。

不幸的是,这种小概率事件又发生了,而且就在我们身边:

事情是这样的——HDU有个网名叫做8006的男性同学,结交网友无数,最近该同学玩起了浪漫,同时给n个网友每人写了1封信,这都没什么,要命的是,他竟然将所有的信都装错了信封!注意了,是全部装错哟!

现在的问题是:请大家帮可怜的8006同学计算1下,1共有多少种可能的错误方式呢?

输入:

输入数据包含多个多个测试实例,每个测试实例占用1行,每行包含1个正整数n(1<n<=20),n表示8006的网友的人数。

输出:

对于每行输入请输出可能的错误方式的数量,每个实例的输出占用1行。

样例输入:

2

3

样例输出:

1

2

#include<stdio、h>

long int F[21];

int main(){

F[1]=0;

F[2]=1;

int i;

for(i=3;i<21;i++)

F[i]=(i-1)*(F[i-1]+F[i-2]);

int n;

while(scanf("%d",&n)!=EOF)

printf("%lld\n",F[n]);

return 0;

}

96、 题目描述:

名名的妈妈从外地出差回来,带了1盒好吃又精美的巧克力给名名(盒内共有 N 块巧克力,20 > N >0)。

妈妈告诉名名每天可以吃1块或者两块巧克力。

假设名名每天都吃巧克力,问名名共有多少种不同的吃完巧克力的方案。

示例:

如果N=1,则名名第1天就吃掉它,共有1种方案;

如果N=2,则名名可以第1天吃1块,第2天吃1块,也可以第1天吃2块,共有2种方案;

如果N=3,则名名第1天可以吃1块,剩2块,也可以第1天吃2块剩1块,所以名名共有2+1=3种方案;

如果N=4,则名名可以第1天吃1块,剩3块,也可以第1天吃2块,剩2块,共有3+2=5种方案。

现在给定N,请你写程序求出名名吃巧克力的方案数目。

输入:

输入只有1行,即整数N。

输出:

可能有多组测试数据,对于每组数据,

输出只有1行,即名名吃巧克力的方案数。

样例输入:

4

样例输出:

5

#include<stdio、h>

int js(int x,int y)

{int n,p=1,q=1,i;

n=x-y;

for(i=1;i<=y;i++)

p=p*i;

for(i=n-y+1;i<=n;i++)

q=q*i;

p=q/p;

return p;

}

int main()

{int i,k,z,n;

while(scanf("%d",&n)!=EOF)

{k=n/2;

z=1;

for(i=1;i<=k;i++)

z+=js(n,i);

printf("%d\n",z);

}

return 0;

}

97、 题目描述:

某国为了防御敌国的导弹袭击,开发出1种导弹拦截系统。但是这种导弹拦截系统有1个缺陷:虽然它的第1发炮弹能够到达任意的高度,但是以后每1发炮弹都不能高于前1发的高度。某天,雷达捕捉到敌国的导弹来袭,并观测到导弹依次飞来的高度,请计算这套系统最多能拦截多少导弹。拦截来袭导弹时,必须按来袭导弹袭击的时间顺序,不允许先拦截后面的导弹,再拦截前面的导弹。

输入:

每组输入有两行,

第1行,输入雷达捕捉到的敌国导弹的数量k(k<=25),

第2行,输入k个正整数,表示k枚导弹的高度,按来袭导弹的袭击时间顺序给出,以空格分隔。

输出:

每组输出只有1行,包含1个整数,表示最多能拦截多少枚导弹。

样例输入:

8

300 207 155 300 299 170 158 65

样例输出:

6

#include<stdio、h>

#include<string、h>

#include<stdlib、h>

#include<math、h>

int max;int n;

void  fun(int a[100],int i,int count)

{

 if(count>max){max=count ;}

 int j=0;

 for(j=i+1;j<n;j++)

 {

   if(a[j]<=a[i])

    {

     fun(a,j,count+1);

    }

 } 

}

int main()

{

  int a[100];int i=0;

  while(scanf("%d",&n)!=EOF)

  {

   max=0;

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

  {

   scanf("%d",&a[i]);

  } 

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

  {

   fun(a,i,1);

  }

  printf("%d\n",max);

  }

  return 0;

}

98、 题目描述:

N位同学站成1排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学不交换位置就能排成合唱队形。

合唱队形是指这样的1种队形:设K位同学从左到右依次编号为1, 2, …, K,他们的身高分别为T1, T2, …, TK,

则他们的身高满足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (1 <= i <= K)。

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

输入:

输入的第1行是1个整数N(2 <= N <= 100),表示同学的总数。

第1行有n个整数,用空格分隔,第i个整数Ti(130 <= Ti <= 230)是第i位同学的身高(厘米)。

输出:

可能包括多组测试数据,对于每组数据,

输出包括1行,这1行只包含1个整数,就是最少需要几位同学出列。

样例输入:

8

186 186 150 200 160 130 197 220

样例输出:

4

#include <stdio、h>

#include <string、h>

#define UNSOLVE -1

#define NMAX 102

#define MMX 240

int n;

int left[NMAX], right[NMAX];

int arr[NMAX];

void init_left() {

for (int i = 0; i < n; ++ i) {

int max = 1;

for (int j = 0; j < i; ++ j) {

  if (arr[i] > arr[j])

 max = max > left[j] + 1 ? max : left[j] + 1;

}

left[i] = max;

}

}

void init_right() {

for (int i = n - 1; i >= 0; -- i) {

int max = 1;

for (int j = i + 1; j < n; ++ j) {

  if (arr[i] > arr[j])

 max = max > right[j] + 1 ? max : right[j] + 1;

}

right[i] = max;

}

}

bool init() {

if (scanf("%d", &n) == EOF) return false;

for (int i = 0; i < n; ++ i) scanf("%d", &arr[i]);

return true;

}

int solve() {

init_left();

init_right();

int min = n;

for (int i = 0; i < n; ++ i) {

int temp = n - (left[i] + right[i] - 1);

min = min < temp ? min : temp;

}

return min;

}

int main() {

while (init()) {

printf("%d\n", solve());

}

return 0;

}

99、 题目描述:

Find a longest common subsequence of two strings、

输入:

First and second line of each input case contain two strings of lowercase character a…z、 There are no spaces before, inside or after the strings、 Lengths of strings do not exceed 100、

输出:

For each case, output k – the length of a longest common subsequence in one line、

样例输入:

abcd

cxbydz

样例输出:

2

#include<iostream>

#include<string、h>

using namespace std;

char str1[110],str2[110];

int Common(int a,int b)

{

 if(a==-1||b==-1)

  return 0;

 if(str1[a]==str2[b])

  return Common(a-1,b-1)+1;

 else

  return Common(a-1,b)>Common(a,b-1)?Common(a-1,b):Common(a,b-1);

}

int main()

{

 int len;

 while(cin>>str1>>str2)

 {

  len=0;

  len=Common(strlen(str1) 1,strlen(str2) 1);

  cout<<len<<endl;

 }

 return 0;

}

100、 题目描述:

搬寝室是很累的,xhd深有体会、时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了、看着寝室里的n件物品,xhd开始发呆,因为n是1个小于2000的整数,实在是太多了,于是xhd决定随便搬2*k件过去就行了、但还是会很累,因为2*k也不小是1个不大于n的整数、幸运的是xhd根据多年的搬东西的经验发现每搬1次的疲劳度是和左右手的物品的重量差的平方成正比(这里补充1句,xhd每次搬两件东西,左手1件右手1件)、示例xhd左手拿重量为3的物品,右手拿重量为6的物品,则他搬完这次的疲劳度为(6-3)^2 = 9、现在可怜的xhd希望知道搬完这2*k件物品后的最佳状态是怎样的(也就是最低的疲劳度),请告诉他吧。

输入:

每组输入数据有两行,第1行有两个数n,k(2<=2*k<=n<2000)、第2行有n个整数分别表示n件物品的重量(重量是1个小于2^15的正整数)、

输出:

对应每组输入数据,输出数据只有1个表示他的最少的疲劳度,每个1行、

样例输入:

2 1

1 3

样例输出:

4

#include <cstdio>

#include <cstring>

#include <algorithm>

using namespace std;

int main()

{

const int MAX_SIZE=2000;

int w[MAX_SIZE];

int n,k;

while(scanf("%d%d",&n,&k)>0)

{

 int i,j;

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

 {

     scanf("%d",&w[i]);

 }

 sort(w,w+n);

 for(i=0;i<n-1;i++)

 {

     w[i]=w[i+1]-w[i];

     w[i]*=w[i];

 }

 int minid,prev,next;

 int rslt=0;

 for(i=0;i<k;i++)

 {

     minid=-1;

     for(j=0;j<n-1;j++)

     {

  if(w[j]<0)   continue;

  if(minid<0 || w[j]<w[minid])  minid=j;

     }

     rslt+=w[minid];

     if(i==k-1)  break;

  

     for(prev=minid-1;prev>=0;prev--)

  if(w[prev]>=0)   break;

     for(next=minid+1;next<n-1;next++)

  if(w[next]>=0)   break;

     if(prev>=0 && next<n-1)   w[minid]=w[prev]+w[next]-w[minid];

     else    w[minid]=-1;

     if(prev>=0)  w[prev]=-1;

     if(next<n-1) w[next]=-1;

 }

 printf("%d\n",rslt);

}

return 0;

}

101、 题目描述:

Tino wrote a long long story、 BUT! in Chinese、、、

So I have to tell you the problem directly and discard his long long story、 That is tino want to carry some oranges with "Carrying pole", and he must make two side of the Carrying pole are the same weight、 Each orange have its' weight、 So greedy tino want to know the maximum weight he can carry、

输入:

The first line of input contains a number t, which means there are t cases of the test data、

for each test case, the first line contain a number n, indicate the number of oranges、

the second line contains n numbers, Wi, indicate the weight of each orange

n is between 1 and 100, inclusive、 Wi is between 0 and 2000, inclusive、 the sum of Wi is equal or less than 2000、

输出:

For each test case, output the maximum weight in one side of Carrying pole、 If you can't carry any orange, output -1、 Output format is shown in Sample Output、

样例输入:

1

5

1 2 3 4 5

样例输出:

Case 1: 7

#include <cstdio>

#include <cstring>

using namespace std;

int max(int a,int b)    {return (a>=b)?a:b;}

int min(int a,int b)    {return (a<=b)?a:b;}

int main()

{

const int MAX_SUM_WEIGHT=2000;

int dp[2][MAX_SUM_WEIGHT/2+1],op,np;

const int MAX_SIZE=100;

int w[MAX_SIZE];

int tc,tcase=1;

int n;

scanf("%d",&tc);

while(tc--)

{

 int i,j;

 bool has_zero=false;

 scanf("%d",&n);

 j=0;

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

 {

     scanf("%d",&w[i]);

     j+=w[i];

 }

 op=0;

 np=1;

 int lmt=j/2+1;

 memset(dp[op],-1,lmt*sizeof(int));

 dp[op][0]=0;

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

 {

     if(w[i]==0)

     {

  has_zero=true;

  continue;

     }

     memcpy(dp[np],dp[op],lmt*sizeof(int));

     //for(j=0;j<lmt;j++) dp[np][j]=dp[op][j];

     for(j=0;j<lmt;j++)

     {

  if(dp[op][j]<0)  continue;

  if(j+w[i]<lmt)   dp[np][j+w[i]]=max(dp[np][j+w[i]],dp[op][j]);

  if(j-w[i]>=0)    dp[np][j-w[i]]=max(dp[np][j-w[i]],dp[op][j]+w[i]);

  else     dp[np][w[i]-j]=max(dp[np][w[i]-j],dp[op][j]+j);

     }

     op=np;

     np=1-op;

 }

 printf("Case %d: %d\n",tcase++,((dp[op][0]>0)?dp[op][0]:(has_zero?0:-1)));

}

return 0;

}

/*

5

1 2 3 4 5

7

10

50 9 8 8 8 8 8 8 8 3

59

12

8 8 50 8 8 3 8 8 8 9 51 7

84

*/

102、 题目描述:

辰辰是个很有潜能、天资聪颖的孩子,他的梦想是称为世界上最伟大的医师。

为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了1个难题。

医师将他带到个到处都是草药的山洞里对他说:

“孩子,这个山洞里有1些不同的草药,采每1株都需要1些时间,每1株也有它自身的价值。

我会给你1段时间,在这段时间里,你可以采到1些草药。如果你是1个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入:

输入的第1行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),T代表总共能够用来采药的时间,M代表山洞里的草药的数目。

接下来的M行每行包括两个在1到100之间(包括1和100)的的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出:

可能有多组测试数据,对于每组数据,

输出只包括1行,这1行只包含1个整数,表示在规定的时间内,可以采到的草药的最大总价值。

样例输入:

70 3

71 100

69 1

1 2

样例输出:

3

#include<stdio、h>

#include<stdlib、h>

int max2int(int a,int b)

{

if(a>b)

{

 return a;

}

return b;

}

int getmaxvalue(int* the_time,int* values,int num,int totaltime)

{

/*输入 the_time是每1项的时间

 * values是每1项的价值

 * num是总的项数

 * totaltime是最大可用时间

 *

 * 输出为能够取到的最大值

 * */

int* ans=(int*)malloc((totaltime+1)*sizeof(int));

int i,j,maxvalue;

for(i=0;i!=(totaltime+1);i++)

{

 ans[i]=0;

}

for(i=0;i!=num;i++)

{

 for(j=totaltime;j>=0;j--)

 {

     if(j-the_time[i]>=0)

     {

  ans[j]=max2int(ans[j],ans[j-the_time[i]]+values[i]);

     }

 }

}

maxvalue=ans[totaltime];

free(ans);

return maxvalue;

}

int main(int argc,char** argv)

{

int *the_time,*values,t,m,i;

while(scanf("%d%d",&t,&m)!=EOF)

{

 the_time=(int*)malloc(m*sizeof(int));

 values=(int*)malloc(m*sizeof(int));

 for(i=0;i<m;i++)

 {

     scanf("%d%d",the_time+i,values+i);

 }

 printf("%d\n",getmaxvalue(the_time,values,m,t));

 free(the_time);

 free(values);

}

return 0;

}

103、 题目描述:

Before ACM can do anything, a budget must be prepared and the necessary financial support obtained、 The main income for this action comes from Irreversibly Bound Money (IBM)、 The idea behind is simple、 Whenever some ACM member has any small money, he takes all the coins and throws them into a piggy-bank、 You know that this process is irreversible, the coins cannot be removed without breaking the pig、 After a sufficiently long time, there should be enough cash in the piggy-bank to pay everything that needs to be paid、

But there is a big problem with piggy-banks、 It is not possible to determine how much money is inside、 So we might break the pig into pieces only to find out that there is not enough money、 Clearly, we want to avoid this unpleasant situation、 The only possibility is to weigh the piggy-bank and try to guess how many coins are inside、 Assume that we are able to determine the weight of the pig exactly and that we know the weights of all coins of a given currency、 Then there is some minimum amount of money in the piggy-bank that we can guarantee、 Your task is to find out this worst case and determine the minimum amount of cash inside the piggy-bank、 We need your help、 No more prematurely broken pigs!

输入:

The input consists of T test cases、 The number of them (T) is given on the first line of the input file、 Each test case begins with a line containing two integers E and F、 They indicate the weight of an empty pig and of the pig filled with coins、 Both weights are given in grams、 No pig will weigh more than 10 kg, that means 1 <= E <= F <= 10000、 On the second line of each test case, there is an integer number N (1 <= N <= 500) that gives the number of various coins used in the given currency、 Following this are exactly N lines, each specifying one coin type、 These lines contain two integers each, Pand W (1 <= P <= 50000, 1 <= W <=10000)、 P is the value of the coin in monetary units, W is it's weight in grams、

输出:

Print exactly one line of output for each test case、 The line must contain the sentence "The minimum amount of money in the piggy-bank is X、" where X is the minimum amount of money that can be achieved using coins with the given total weight、 If the weight cannot be reached exactly, print a line "This is impossible、"、

样例输入:

3

10 110

2

1 1

30 50

10 110

2

1 1

50 30

1 6

2

10 3

20 4

样例输出:

The minimum amount of money in the piggy-bank is 60、

The minimum amount of money in the piggy-bank is 100、

This is impossible、

#include <cstdio>

#include <cstring>

const long long  INF = 999999999;

const int MAX = 501;

const int MAXWEIGH = 10004;

int T,E,F,N,P,W,values[MAX],weigh[MAX];

long long dp[MAXWEIGH];

long long min(long long a, long long b)

{

return a > b ? b : a;

}

int main()

{

//freopen("in、txt", "r", stdin);

scanf("%d", &T);

while (T-- > 0)

{

 memset(values, 0, sizeof(int)*MAX);

 memset(weigh, 0, sizeof(int)*MAX);

 for (int i = 0; i < MAXWEIGH; ++i) dp[i] = INF;

 scanf("%d %d", &E, &F);

 scanf("%d", &N);

 for (int i = 0; i < N; ++i) scanf("%d %d", &values[i],&weigh[i]);

 //algorithm start

 int need = F - E;

 for (int i = 1; i <= N; ++i)

 {

     dp[0] = 0;

     for (int j = weigh[i-1]; j <= need; ++j)

     {

  dp[j] = min(dp[j], dp[j - weigh[i - 1]] + values[i - 1]);

     }

 }

 if (dp[need] < INF)

     printf("The minimum amount of money in the piggy-bank is %lld、\n", dp[need]);

 else printf("This is impossible、\n");

}

//fclose(stdin);

return 0;

}

104、 题目描述:

为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购1些粮食支援灾区,现在假设你1共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。请问:你用有限的资金最多能采购多少公斤粮食呢?

输入:

输入数据首先包含1个正整数C,表示有C组测试用例,每组测试用例的第1行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。

输出:

对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占1行。

样例输入:

1

8 2

2 100 4

4 100 2

样例输出:

400

#include <cstdio>

#include <string、h>

using namespace std;

int cs,M,N;

int rice[105][3];

int cost[105];

void package(int m,int w)

{

for (int i=N;i>=m;--i)

{

 cost[i] = cost[i-m]+w>cost[i]?cost[i-m]+w:cost[i];

}

}

int main(void)

{

scanf("%d",&cs);

while (cs--)

{

 memset(cost,0,sizeof(cost));

 scanf("%d%d",&N,&M);

 for (int i=0;i<M;++i)

 {

     scanf("%d%d%d",&rice[i][0],&rice[i][1],&rice[i][2]);

 }

 for (int i=0;i<M;++i)

 {

     for (int j=0;j<rice[i][2];++j)

     {

  package(rice[i][0],rice[i][1]);

     }

 }

 printf("%d\n",cost[N]);

}

return 0;

}

105、 题目描述:

给定1个短string(不含空格),再给定若干string,在这些string中删除所含有的短string。

输入:

输入只有1组数据。

输入1个短string(不含空格),再输入若干string直到文件结束为止。

输出:

删除输入的短string(不区分大小写)并去掉空格,输出。

样例输入:

in

#include

int main()

{

printf(" Hi ");

}

样例输出:

#clude

tma()

{

prtf("Hi");

}

#include<iostream>

#include<string>

using namespace std;

int main()

{

string s1;

char s[1000];

cin>>s1;

int j;

string s2;

string::iterator i;

cin、ignore();

while(cin、getline(s,1000))

{

s2=s;

while(s2、find(s1)!=string::npos)

{

i=s2、begin()+s2、find(s1);

s2、erase(i,i+s1、length());

}

while(s2、find(' ')!=string::npos)

{

i=s2、begin()+s2、find(' ');

s2、erase(i);

}

cout<<s2<<endl;

}

return 0;

}

106、 题目描述:

输入1个string,以回车结束(string长度<=100)。该string由若干个单词组成,单词之间用1个空格隔开,所有单词区分大小写。现需要将其中的某个单词替换成另1个单词,并输出替换之后的string。

输入:

多组数据。每组数据输入包括3行,

第1行是包含多个单词的string s,

第2行是待替换的单词a,(长度<=100)

第3行是a将被替换的单词b。(长度<=100)

s, a, b 最前面和最后面都没有空格、

输出:

每个测试数据输出只有 1 行,

将s中所有单词a替换成b之后的string。

样例输入:

You want someone to help you

You

I

样例输出:

I want someone to help you

#include<iostream>

#include<fstream>

#include<string>

#include<algorithm>

using namespace std;

int main()

{

 string a,b,s;

// fstream cin("1111、txt");

 while (getline(cin,s))

 {

  cin>>a>>b;

  string::size_type pos=0;

  while((pos=s、find(a,pos))!=string::npos)

  {

   if (pos==0)

   {

    s、replace(pos,a、size(),b);

    pos++;

   }

   else if (s[pos-1]==' '&&(s[pos+a、size()]==' '||s[pos+a、size()]=='\0'))

   {

    s、replace(pos,a、size(),b);

    pos++;

   }

   else

   {

    pos++;

   }

  }

  cout<<s<<endl;

  cin、ignore();

 }

 return 0;

}

107、 题目描述:

输入strings和字符c,要求去掉s中所有的c字符,并输出结果。

输入:

测试数据有多组,每组输入strings和字符c。

输出:

对于每组输入,输出去除c字符后的结果。

样例输入:

heallo

a

样例输出:

Hello

#include <stdio、h>

#include <string、h>

int main()

{

 char str[1000000],ch,ch1;

 int len,i;

 while (gets(str))

 {

  scanf("%c",&ch);

  len = strlen(str);

  for (i=0;i<len;i++)

  {

   if (str[i] != ch)

    printf("%c",str[i]);

  }

  printf("\n");

  ch1 = getchar();

 }

 return 0;

}

108、 题目描述:

对给定的string(只包含'z','o','j'三种字符),判断他是否能AC。

是否AC的要求如下:

1、 zoj能AC;

2、 若string形式为xzojx,则也能AC,其中x可以是N个'o' 或者为空;

3、 若azbjc 能AC,则azbojac也能AC,其中a,b,c为N个'o'或者为空;

输入:

输入包含多组测试用例,每行有1个只包含'z','o','j'三种字符的string,string长度小于等于1000。

输出:

对于给定的string,如果能AC则请输出string“Accepted”,否则请输出“Wrong Answer”。

样例输入:

zoj

ozojo

ozoojoo

oozoojoooo

zooj

ozojo

oooozojo

zojoooo

样例输出:

Accepted

Accepted

Accepted

Accepted

Accepted

Accepted

Wrong Answer

Wrong Answer

#include <iostream>

using namespace std;

int main() {

 string str;

 while(cin >> str){

  int count1 = 0, count2 = 0;

  const char *pchar = str、c_str();

  int i = 0;

  while(pchar[i] == 'o'){

   count1++;

   i++;

  }

  if(pchar[i] != 'z'){

   cout << "Wrong Answer" <<endl;

   continue;

  }

  i++;

  if(pchar[i] != 'o'){

   cout << "Wrong Answer" <<endl;

   continue;

  }

  while(pchar[i] == 'o'){

   i++;

  }

  if(pchar[i] != 'j'){

   cout << "Wrong Answer" <<endl;

   continue;

  }

  i++;

  while(pchar[i] == 'o'){

   count2++;

   i++;

  }

  if(count1 <= count2 && pchar[i] == 0){

   if(count1 ==0 && count2 != 0){

    cout << "Wrong Answer" <<endl;

    continue;

   }

   cout << "Accepted" <<endl;

  }

  else{

   cout << "Wrong Answer" <<endl;

  }

 }

 return 0;

}

109、 题目描述:

按要求,给国家进行排名。

输入:

有多组数据。

第1行给出国家数N,要求排名的国家数M,国家号从0到N-1。

第2行开始的N行给定国家或地区的奥运金牌数,奖牌数,人口数(百万)。

接下来1行给出M个国家号。

输出:

排序有4种方式: 金牌总数 奖牌总数 金牌人口比例 奖牌人口比例

对每个国家给出最佳排名排名方式 和 最终排名

格式为: 排名:排名方式

如果有相同的最终排名,则输出排名方式最小的那种排名,对于排名方式,金牌总数 < 奖牌总数 < 金牌人口比例 < 奖牌人口比例

如果有并列排名的情况,即如果出现金牌总数为 100,90,90,80、则排名为1,2,2,4、

每组数据后加1个空行。

样例输入:

4 4

4 8 1

6 6 2

4 8 2

2 12 4

0 1 2 3

4 2

8 10 1

8 11 2

8 12 3

8 13 4

0 3

样例输出:

1:3

1:1

2:1

1:2

1:1

1:1

#include <iostream>

#include <algorithm>

#include <cstdio>

#include <cstring>

using namespace std;

const int Maxn = 100000;

struct Con{

 double God,Pri,Peo;

 double Godper,Peoper;

 int id;

}P[Maxn],rp[Maxn];

int rank[Maxn];

int N,M;

bool cmp(const Con a, const Con b)

{

 return a、Peoper>b、Peoper;

}

bool cmp1(const Con a, const Con b)

{

 return a、Godper>b、Godper;

}

bool cmp2(const Con a, const Con b)

{

 return a、Pri>b、Pri;

}

bool cmp3(const Con a, const Con b)

{

 return a、God>b、God;

}

int main()

{

 int i,index[Maxn],j;

 int bet,way;

 while(scanf("%d%d",&N,&M)!=EOF)

 {

  for(i = 0; i<N; i++)

  {

   cin>>rp[i]、God>>rp[i]、Pri>>rp[i]、Peo;

   rp[i]、Godper = rp[i]、God/rp[i]、Peo;

   rp[i]、Peoper = rp[i]、Pri/rp[i]、Peo;

  }

  int r = 0;

  for(i = 0; i<M; i++)

  {

   cin>>index[i];

   P[r] = rp[index[i]];

   P[r++]、id = index[i];

  }

  for(i = 0; i<M; i++)

  {

   sort(P,P+M,cmp3);

   rank[0] = 1;

   for(j = 1; j<M; j++)

   if(P[j]、God == P[j-1]、God)rank[j] = rank[j-1];

   else rank[j] = j+1;

   for(j = 0; j<M; j++)

    if(P[j]、id == index[i])

    { 

      bet = rank[j];

      way = 1;

      break;

    }

   sort(P,P+M,cmp2);

   rank[0] = 1;

   for(j = 1; j<M; j++)

   if(P[j]、Pri == P[j-1]、Pri)rank[j] = rank[j-1];

   else rank[j] = j+1;

   for(j = 0; j<M; j++)

    if(P[j]、id == index[i])

    { 

     if(rank[j]<bet)

     {

      bet = rank[j];

      way = 2;

     }

     break;

    }  

   sort(P,P+M,cmp1);

   rank[0] = 1;

   for(j = 1; j<M; j++)

   if(P[j]、Godper == P[j-1]、Godper)rank[j] = rank[j-1];

   else rank[j] = j+1;

   for(j = 0; j<M; j++)

    if(P[j]、id == index[i])

    { 

     if(rank[j]<bet)

     {

      bet = rank[j];

      way = 3;

     }

     break;

    }

   sort(P,P+M,cmp);

   rank[0] = 1;

   for(j = 1; j<M; j++)

   if(P[j]、Peoper == P[j-1]、Peoper)rank[j] = rank[j-1];

   else rank[j] = j+1;

   for(j = 0; j<M; j++)

    if(P[j]、id == index[i])

    {

     if(rank[j]<bet)

     {

      bet = rank[j];

      way = 4;

     }

     break;

    }

   printf("%d:%d\n",bet,way);

  }

  printf("\n");

  

 }

 return 0;

}

#include<stdio、h>

#include<algorithm>

using namespace std;

#define N 300 //根据实际情况定义大小,全世界只有200多个国家和地区

struct Country { //国家结构体,存储相关信息

int id;

int gold;

int medal;

int population;

}country1[N], country2[N];

bool cmp1(Country a, Country b) { //按金牌数降序排列

return a、gold > b、gold;

}

bool cmp2(Country a, Country b) {

return a、medal > b、medal;

}

//注意定义时gold,medal和population都是整数,因此求人均时必须先化为浮点数,

//否则会出现本来人际不同,但取整后相同的情况

bool cmp3(Country a, Country b) {

return a、gold*1、0/a、population > b、gold*1、0/b、population;

}

bool cmp4(Country a, Country b) {

return a、medal*1、0/a、population > b、medal*1、0/b、population;

}

int rankid[N]; //存放需要排名的国家号

int rankc[N]; //存放需要排名的国家的最好名次

int rankway[N]; //存放需要排名的国家的最好名次对应的排列方式

int main() {

//freopen("in、txt","r",stdin);

int n, m;

while(scanf("%d %d",&n,&m)!=EOF) {

 int i, j, k;

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

     country1[i]、id = i; //按输入顺序给国家编号,从0开始

     scanf("%d %d %d",&country1[i]、gold,&country1[i]、medal,&country1[i]、population);

 }

 for(i=0; i<m; i++) { //记录需要排名的国家号

     scanf("%d",&rankid[i]);

 }

 for(i=0; i<m; i++) { //将需要排名的国家存放到另外1个结构体数组,方便排序

     for(j=0; j<n; j++) {

  if(rankid[i] == country1[j]、id) {

      country2[i] = country1[j];

      break;

  }

     }

 }

 sort(country2,country2+m,cmp1); //按金牌数降序排列

 for(i=0; i<m; i++) {

     for(j=0; j<m; j++) { //遍历已排好序的结构体数组,找到当前国家的名次

  if(rankid[i] == country2[j]、id) {

      for(k=0; k<m; k++) {

   if(country2[k]、gold == country2[j]、gold) { //处理同名次的情况,以第1次出现为准

       rankc[i] = k+1; //暂存当前最优名次

       rankway[i] = 1; //暂存对应的排序方式

       break;

   }

      }

      break;

  }  

     }

 }

 sort(country2,country2+m,cmp2);

 for(i=0; i<m; i++) {

     for(j=0; j<m; j++) {

  if(rankid[i] == country2[j]、id) {

      for(k=0; k<m; k++) {

   if(country2[k]、medal == country2[j]、medal) {

       if(k+1 < rankc[i]) { //若此时名次更好,则更新最优名次和对应的排序方式

    rankc[i] = k+1;  //因为是按排序方式由小到大的顺序处理的,所以无需考虑同名次时更新排序方式

    rankway[i] = 2;

       }

       break;

   }

      }    

      break;

  }

     }

 }

 sort(country2,country2+m,cmp3);

 for(i=0; i<m; i++) {

     for(j=0; j<m; j++) {

  if(rankid[i] == country2[j]、id) {

      for(k=0; k<m; k++) {

   if(country2[k]、gold*1、0/country2[k]、population == country2[j]、gold*1、0/country2[j]、population) {

       if(k+1 < rankc[i]) {

    rankc[i] = k+1;

    rankway[i] = 3;

       }

       break;

   }

      }    

      break;

  }

     }

 }

 sort(country2,country2+m,cmp4);

 for(i=0; i<m; i++) {

     for(j=0; j<m; j++) {

  if(rankid[i] == country2[j]、id) {

      for(k=0; k<m; k++) {

   if(country2[k]、medal*1、0/country2[k]、population == country2[j]、medal*1、0/country2[j]、population) {

       if(k+1 < rankc[i]) {

    rankc[i] = k+1;

    rankway[i] = 4;

       }

       break;

   }

      }    

      break;

  }

     }

 }

 for(i=0; i<m; i++) { //按照需要排序国家的国家号从小到大输出对应信息

     printf("%d:%d\n",rankc[i],rankway[i]);

 }

 printf("\n");

}

return 0;

}

110、 题目描述:

读入两个小于100的正整数A和B,计算A+B、

需要注意的是:A和B的每1位数字由对应的英文单词给出、

输入:

测试输入包含若干测试用例,每个测试用例占1行,格式为"A + B =",相邻两string有1个空格间隔、当A和B同时为0时输入结束,相应的结果不要输出、

输出:

对每个测试用例输出1行,即A+B的值、

样例输入:

one + two =

three four + five six =

zero seven + eight nine =

zero + zero =

样例输出:

3

90

96

#include <iostream>

#include <string>

#include <map>

using namespace std;

string str;

string Num[10] = {"zero","one","two","three","four","five","six","seven","eight","nine"};

map<string, int>Q;

void init()

{

 for(int i = 0; i<10; i++)

  Q[Num[i]] = i;

}

int main()

{

 int i,a,b,len,flag;

 //freopen("in、txt","r",stdin);

 init();

 while(getline(cin,str))

 {

  a = b = flag = 0;

  len = str、size();

  for(i = 0; i<len; i++)

  {

   string op = "";

   while(str[i]!=' '&&i<len)

   {

    op+=str[i];

    i++;

   }

   if(op[0] == '+'||op[0] == '=')

   {

    flag = 1;

    continue;

   }

   if(!flag)a = a*10+Q[op];

   else b = b*10+Q[op];

  }

  if(a == 0 && b == 0)break;

  else

   cout<<a+b<<endl;

 }

 return 0; 

}

111、 题目描述:

给定K个整数的序列{ N1, N2, 、、、, NK },其任意连续子序列可表示为{ Ni, Ni+1, 、、、, Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序列中元素和最大的1个,示例给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20。现在增加1个要求,即还需要输出该子序列的第1个和最后1个元素。

输入:

测试输入包含若干测试用例,每个测试用例占2行,第1行给出正整数K( K< 10000 ),第2行给出K个整数,中间用空格分隔。当K为0时,输入结束,该用例不被处理。

输出:

对每个测试用例,在1行里输出最大和、最大连续子序列的第1个和最后1个元素,中间用空格分隔。如果最大连续子序列不唯1,则输出序号i和j最小的那个(如输入样例的第2、3组)。若所有K个元素都是负数,则定义其最大和为0,输出整个序列的首尾元素。

样例输入:

6

-2 11 -4 13 -5 -2

10

-10 1 2 3 4 -5 -23 3 7 -21

6

5 -8 3 2 5 0

1

10

3

-1 -5 -2

3

-1 0 -2

0

样例输出:

20 11 13

10 1 4

10 3 5

10 10 10

0 -1 -2

0 0 0

#include<stdio、h>

#define Max 10000

int main(){

 int maxsofar;

 int maxendinghere;

 int begin,end,temp;

 int x[Max];

 int i,n;

 int count;

 while(scanf("%d",&n),n>0){

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

   scanf("%d",&x[i]);

  count = 0;

  maxsofar = maxendinghere = 0;

  begin = end = temp = 0;

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

   if(x[i]<0) count++;

   maxendinghere += x[i];

   if(maxendinghere<=0){

    maxendinghere = 0;

    temp = i+1;

   }

   if(maxendinghere>maxsofar){

    maxsofar = maxendinghere;

    begin = temp;

    end = i;

   }

   if(maxendinghere==0&&maxsofar==0&&x[i]==0)

    end = begin = i;

  }

  if(count==n) printf("0 %d %d\n",x[0],x[n-1]);

  else

   printf("%d %d %d\n",maxsofar,x[begin],x[end]);

 }

}

112、 题目描述:

每天第1个到机房的人要将门打开,最后1个离开的人要将门关好。现有1堆杂乱的机房签到、签离记录,请根据记录找出当天开门和关门的人。

输入:

测试输入的第1行给出记录的总天数N ( N> 0 ),下面列出了N天的记录。

每天的记录在第1行给出记录的条目数M (M > 0 ),下面是M行,每行的格式为

证件号码 签到时间 签离时间

其中时间按“小时:分钟:秒钟”(各占2位)给出,证件号码是长度不超过15的string。

输出:

对每1天的记录输出1行,即当天开门和关门人的证件号码,中间用1空格分隔。

注意:在裁判的标准测试输入中,所有记录保证完整,每个人的签到时间在签离时间之前,且没有多人同时签到或者签离的情况。

样例输入:

3

1

ME3021112225321 00:00:00 23:59:59

2

EE301218 08:05:35 20:56:35

MA301134 12:35:45 21:40:42

3

CS301111 15:30:28 17:00:10

SC3021234 08:00:00 11:25:25

CS301133 21:45:00 21:58:40

样例输出:

ME3021112225321 ME3021112225321

EE301218 MA301134

SC3021234 CS301133

#include<stdio、h>

#include<string、h>

int main()

{

 int m,n,i,j;

 char id[16],a[16],b[16];

 int eh,em,es,lh,lm,ls;

 int ehh,emm,ess,lhh,lmm,lss;

 while(scanf("%d",&n)!=EOF)

 {

  if(n<=0)

  {

   return 0;

  }

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

  {

   scanf("%d",&m);

   if(m<=0)

   {

    return 0;

   }

   scanf("%s %d:%d:%d %d:%d:%d",id,&ehh,&emm,&ess,&lhh,&lmm,&lss);

   eh=ehh;em=emm;es=ess;

   lh=lhh;lm=lmm;ls=lss;

   strcpy(a,id);strcpy(b,id);

   for(j=1;j<m;j++)

   {

    scanf("%s %d:%d:%d %d:%d:%d",id,&ehh,&emm,&ess,&lhh,&lmm,&lss);

    if((ehh<eh)||((ehh==eh)&&(emm<em))||((ehh==eh)&&(emm==em)&&(ess<es)))

    {

     strcpy(a,id);

    }

    if((lhh>lh)||((lhh==lh)&&(lmm>lm))||((lhh==lh)&&(lmm==lm)&&(lss>ls)))

    {

     strcpy(b,id);

    }

   }

   printf("%s %s\n",a,b);

  }

 }

 return 0;

}

113、 题目描述:

今天的上机考试虽然有实时的Ranklist,但上面的排名只是根据完成的题数排序,没有考虑每题的分值,所以并不是最后的排名。给定录取分数线,请你写程序找出最后通过分数线的考生,并将他们的成绩按降序打印。

输入:

测试输入包含若干场考试的信息。每场考试信息的第1行给出考生人数N ( 0 < N < 1000 )、考题数M ( 0 < M < = 10 )、分数线(正整数)G;第2行排序给出第1题至第M题的正整数分值;以下N行,每行给出1名考生的准考证号(长度不超过20的string)、该生解决的题目总数m、以及这m道题的题号(题目号由1到M)。

当读入的考生人数为0时,输入结束,该场考试不予处理。

输出:

对每场考试,首先在第1行输出不低于分数线的考生人数n,随后n行按分数从高到低输出上线考生的考号与分数,其间用1空格分隔。若有多名考生分数相同,则按他们考号的升序输出。

样例输入:

4 5 25

10 10 12 13 15

CS004 3 5 1 3

CS003 5 2 4 1 3 5

CS002 2 1 2

CS001 3 2 3 5

1 2 40

10 30

CS001 1 2

2 3 20

10 10 10

CS000000000000000001 0

CS000000000000000002 2 1 2

0

样例输出:

3

CS003 60

CS001 37

CS004 37

0

1

CS000000000000000002 20

#include <iostream>

#include <cstdio>

#include <algorithm>

#include <string>

using namespace std;

const int Maxn = 1005;

struct Rank{

 string id;

 int sc;

}P[Maxn];

int Op[20];

bool cmp(const Rank a, const Rank b)

{

 if(a、sc>b、sc)return true;

 else if(a、sc == b、sc && a、id<b、id)return true;

 return false;

}

int main()

{

 int N,M,G;

 int i,n,ans,a;

 string str;

 while(cin>>N)

 {

  if(N == 0)break;

  cin>>M>>G;

  for(i = 1; i<=M; i++)

   cin>>Op[i];

  ans = 0;

  for(i = 0; i<N; i++)

  {

   cin>>str;

   cin>>n;

   int sum = 0;

   while(n--)

   {

    cin>>a;

    sum+=Op[a];

   }

   if(sum>=G)

   {

    P[ans]、id = str;

    P[ans++]、sc = sum;

   }

  }

  sort(P,P+ans,cmp);

  cout<<ans<<endl;

  for(i = 0; i<ans; i++)

   cout<<P[i]、id<<' '<<P[i]、sc<<endl; 

 }

 return 0;

}

114、 题目描述:

读入两个不超过25位的火星正整数A和B,计算A+B。需要注意的是:在火星上,整数不是单1进制的,第n位的进制就是第n个素数。示例:地球上的10进制数2,在火星上记为“1,0”,因为火星个位数是2进制的;地球上的10进制数38,在火星上记为“1,1,1,0”,因为火星个位数是2进制的,十位数是3进制的,百位数是5进制的,千位数是7进制的……

输入:

测试输入包含若干测试用例,每个测试用例占1行,包含两个火星正整数A和B,火星整数的相邻两位数用逗号分隔,A和B之间有1个空格间隔。当A或B为0时输入结束,相应的结果不要输出。

输出:

对每个测试用例输出1行,即火星表示法的A+B的值。

样例输入:

1,0 2,1

4,2,0 1,2,0

1 10,6,4,2,1

0 0

样例输出:

1,0,1

1,1,1,0

1,0,0,0,0,0

#include<iostream>

using namespace std;

void change(char str[],int num[],int &j)//将字符转换为数字

{

int i=0;

j=0;

while(str[i]!='\0')

{

if(str[i]<='9'&&str[i]>='0')

{

num[j]=num[j]*10+str[i]-'0';

i++;

}

else {i++;j++;}

}

j++;

}

void reve(int r[],int ri)//为了方便运算 逆转数组

{

int i;

ri=ri-1;

for(i=0;i<=ri/2;i++)

{

int er=r[i];

r[i]=r[ri-i];

r[ri-i]=er;

}

}

int main()

{

 int i;

 int j;

 i=5;

 static int X[50];

 X[0]=2;

 X[1]=3;

 int v=2;

 while(1)

 {

 int temp=1;

 for(j=2;j<i/2;j++)if(i%j==0)temp=0;

 if(temp==1){X[v]=i;v++;}

 if(v==49)break;

 i++;

 }//求素数存于X数组中

 char A[100];

 static int a[50];

 char B[100];

 static int b[50];

 static int ab[50];

 int ai;

 int bi;

 while(cin>>A>>B)//

 {

 if(A[0]=='0'&&B[0]=='0')break;

 for(i=0;i<50;i++)a[i]=b[i]=ab[i]=0;//所有数组赋值 这里系统有1个小BUG 如果直接static初始化数组会悲剧

 change(A,a,ai);//将A转化为数字

 change(B,b,bi);//

reve(a,ai);//反转A的数组a

 reve(b,bi);//

 int C=0;//c用来保存进位 初值为0

 for(i=0;i<=29;i++)//两组数求和 当超过进制时 进位

 {

 ab[i]=(a[i]+b[i]+C)%X[i];

 C=(C+a[i]+b[i]-ab[i])/X[i];

 }

reve(ab,50);//上面求得的答案逆序存在ab数组中 通过逆序再反倒过来

 i=0;

 while(ab[i]==0)i++;//找到储存结果的起始点

while(i<50)//循环输出答案

 {

 cout<<ab[i];

 if(i!=49)cout<<",";//最后1个数字的时候不用输出,号

 i++;

 }

 cout<<endl;//记得结束的时候换行

 }

return 0;

}

115、 题目描述:

给定1系列2维平面点的坐标(x, y),其中x和y均为整数,要求用1个最小的长方形框将所有点框在内。长方形框的边分别平行于x和y坐标轴,点落在边上也算是被框在内。

输入:

测试输入包含若干测试用例,每个测试用例由1系列坐标组成,每对坐标占1行,其中|x|和|y|小于 231;1对0 坐标标志着1个测试用例的结束。注意(0, 0)不作为任何1个测试用例里面的点。1个没有点的测试用例标志着整个输入的结束。

输出:

对每个测试用例,在1行内输出2对整数,其间用1个空格隔开。第1对整数是长方形框左下角的坐标,第2对整数是长方形框右上角的坐标。

样例输入:

12 56

23 56

13 10

0 0

12 34

0 0

0 0

样例输出:

12 10 23 56

12 34 12 34

#include<stdio、h>

int main()

{

 int x,y;

 int minx,miny,maxx,maxy;

 while(scanf("%d %d",&x,&y)&&(x!=0||y!=0))

 {

  minx=256,miny=256,maxx=-256,maxy=-256;

  while(x!=0||y!=0)

  {

   if(x<minx)

    minx=x;

   if(y<miny)

    miny=y;

   if(x>maxx)

    maxx=x;

   if(y>maxy)

    maxy=y;

   scanf("%d %d",&x,&y);

  }

  printf("%d %d %d %d\n",minx,miny,maxx,maxy);

 }

return 0;

}

116、 题目描述:

统计1个给定string中指定的字符出现的次数。

输入:

测试输入包含若干测试用例,每个测试用例包含2行,第1行为1个长度不超过5的string,第2行为1个长度不超过80的string。注意这里的string包含空格,即空格也可能是要求被统计的字符之1。当读到'#'时输入结束,相应的结果不要输出。

输出:

对每个测试用例,统计第1行中string的每个字符在第2行string中出现的次数,按如下格式输出:

c0 n0

c1 n1

c2 n2

、、、

其中ci是第1行中第i个字符,ni是ci出现的次数。

样例输入:

I

THIS IS A TEST

i ng

this is a long test string

#

样例输出:

I 2

i 3

5

n 2

g 2

#include<iostream>

#include<string>

using  namespace std;

int main()

{

 string pa,line;

 int i,j;

 while(getline(cin,pa)&&pa!="#")

 {

  getline(cin,line);

  int co[5]={0};

  for(i=0;i<line、size();i++)

  {

   for(j=0;j<pa、size()&&pa[j]!=line[i];j++);

     co[j]+=j<pa、size();

  }

  for(i=0;i<pa、size();i++)

   {

   cout<<pa[i]<<" "<<co[i]<<endl;

  }

 }

 return 0;

}

117、 题目描述:

现有公园游船租赁处请你编写1个租船管理系统。当游客租船时,管理员输入船号并按下S键,系统开始计时;当游客还船时,管理员输入船号并按下E键,系统结束计时。船号为不超过100的正整数。当管理员将0作为船号输入时,表示1天租船工作结束,系统应输出当天的游客租船次数和平均租船时间。

注意:由于线路偶尔会有故障,可能出现不完整的纪录,即只有租船没有还船,或者只有还船没有租船的纪录,系统应能自动忽略这种无效纪录。

输入:

测试输入包含若干测试用例,每个测试用例为1整天的租船纪录,格式为:

船号(1~100) 键值(S或E) 发生时间(小时:分钟)

每1天的纪录保证按时间递增的顺序给出。当读到船号为-1时,全部输入结束,相应的结果不要输出。

输出:

对每个测试用例输出1行,即当天的游客租船次数和平均租船时间(以分钟为单位的精确到个位的整数时间)。

样例输入:

1 S 08:10

2 S 08:35

1 E 10:00

2 E 13:16

0 S 17:00

0 S 17:00

3 E 08:10

1 S 08:20

2 S 09:00

1 E 09:20

0 E 17:00

-1

样例输出:

2 196

0 0

1 60

#include<stdio、h>

struct{

 int flag; /*标记船有无被借出,借出为1,否则为0*/

 int time;

}boat[101];

int main(){

  int hour,minute,number,temptime;/*number为船号*/

  char S_E;/*标记是租借还是归还*/

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

  if(number == -1) return 0;

   int count = 0;

   double totaltime = 0;

   /*处理number不为0的情况*/

   while(number){

    scanf(" %c %d:%d",&S_E,&hour,&minute);

    temptime = hour * 60 + minute;

    if(S_E == 'S'){/*如果是借出则将借出的该船标记置1,*/

     boat[number]、flag = 1;

     boat[number]、time = temptime;

    }

    else{

     if(boat[number]、flag){/*如果是归还之前已借出的该船 ,则记下时间差值,数目加1,并将标志置0、*/

      totaltime += temptime - boat[number]、time;

      count ++;

      boat[number]、flag = 0;

     }

    }

    scanf("%d",&number);

   }

   /*如果船号为0时,依然正常输入各值,但此时不做处理*/

   scanf(" %c %d:%d",&S_E,&hour,&minute);

   if(count)  totaltime = totaltime/count;

     printf ("%d %、0lf\n",count,totaltime);

 }

 return 0;

}

119、 题目描述:

现有1笔经费可以报销1定额度的发票。允许报销的发票类型包括买图书(A类)、文具(B类)、差旅(C类),要求每张发票的总额不得超过1000元,每张发票上,单项物品的价值不得超过600元。现请你编写程序,在给出的1堆发票中找出可以报销的、不超过给定额度的最大报销额。

输入:

测试输入包含若干测试用例。每个测试用例的第1行包含两个正数 Q 和 N,其中 Q 是给定的报销额度,N(N<=30)是发票张数。随后是 N 行输入,每行的格式为:

m Type_1:price_1 Type_2:price_2 、、、 Type_m:price_m

其中正整数 m 是这张发票上所开物品的件数,Type_i 和 price_i 是第 i 项物品的种类和价值。物品种类用1个大写英文字母表示。当N为0时,全部输入结束,相应的结果不要输出。

输出:

对每个测试用例输出1行,即可以报销的最大数额,精确到小数点后2位。

样例输入:

200、00 3

2 A:23、50 B:100、00

1 C:650、00

3 A:59、99 A:120、00 X:10、00

1200、00 2

2 B:600、00 A:400、00

1 C:200、50

1200、50 3

2 B:600、00 A:400、00

1 C:200、50

1 A:100、00

100、00 0

样例输出:

123、50

1000、00

1200、50

#include<iostream>

#include<stdio、h>

#include<string、h>

#include<iomanip>

#include<math、h>

using namespace std;

double a[31];

int top;

double max(double x,double y){

   if(x>y)return x;

   else return y;

}

double maxvalue(int k,double left,double Q){//递归求最大报销额

//cout<<"left="<<left<<" Q="<<Q<<endl;

int mark=0;

double t=0;

for(int i=k;i<top;i++)

 if(a[i]<=left){

     t=max(maxvalue(i+1,left-a[i],Q),t);

     //cout<<"t="<<t<<endl;

     mark=1;

 }

if(mark==0)return Q-left;

else return t;

} 

int main(void){

double Q,sum,value,total;

int n,m,mark;

char c,d;

while(scanf("%lf%d",&Q,&n)!=EOF){

 if(n==0)break;

 top=0;

 for(int i=0;i<n;i++){

     scanf("%d",&m);

     mark=1;

     sum=0;

     for(int j=0;j<m;j++){

  scanf(" %c:%lf",&c,&value);

  //cout<<"c="<<c<<" value="<<value<<endl;

  if(value>600、00||c-'A'>=3)mark=0;

  sum=sum+value;

     }

     if(mark==1&&sum<=1000、00){

  a[top]=sum;

  //cout<<"top="<<top<<" a["<<top<<"]="<<a[top]<<endl;

  top++;

     }

 }

 printf("%、*lf\n",2,maxvalue(0,Q,Q));

}

return 0;

}

120、 题目描述:

欧拉回路是指不令笔离开纸面,可画过图中每条边仅1次,且可以回到起点的1条回路。现给定1个图,问是否存在欧拉回路?

输入:

测试输入包含若干测试用例。每个测试用例的第1行给出两个正整数,分别是节点数N ( 1 < N < 1000 )和边数M;随后的M行对应M条边,每行给出1对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。当N为0时输入结束。

输出:

每个测试用例的输出占1行,若欧拉回路存在则输出1,否则输出0。

样例输入:

3 3

1 2

1 3

2 3

3 2

1 2

2 3

0

样例输出:

1

0

#include<iostream>

using namespace std;

struct node

{

 int index;

 int rank;

 int key;

 node *p;

};

void make_set(node *n)

{

 n->index=0;

 n->rank=0;

 n->p=n;

}

void union_set(node *n1,node *n2)

{

 if(n1->rank<n2->rank)

  n1->p=n2;

 else

 {

  n2->p=n1;

  if(n1->rank==n2->rank)

   ++n1->rank;

 }

}

node *find_set(node *n)

{

 if(n->p!=n)

  n->p=find_set(n->p);

 return n->p;

}

int main()

{

 int n,m;

 while(cin>>n&&n)

 {

  cin>>m;

  node **a=new node *[n+1];

  for(int i=1;i<=n;++i)

  {

   node *temp=new node;

   temp->key=i;

   make_set(temp);

   a[i]=temp;

  }

  int num=n-1;

  for(int i=1;i<=m;++i)

  {

   int x,y;

   cin>>x>>y;

   ++(a[x]->index);

   ++(a[y]->index);

   if(find_set(a[x])!=find_set(a[y]))

   {

    union_set(a[x],a[y]);

    --num;

   }

  }

  bool b=true;

  for(int i=1;i<=n;++i)

  {

   if((a[i]->index)%2!=0)

   {

    b=false;

    break;

   }

  }

  if(b&&!num)

   cout<<1<<endl;

  else

   cout<<0<<endl;

 }

 return 0;

}

3 JAVA方面算法难题(50道,中等难度)

程序1。

题目:古典问题:有1对兔子,从出生后第3个月起每个月都生1对兔子,小兔子长到第三个月后每个月又生1对兔子,假如兔子都不死,问每个月的兔子总数为多少?

//这是1个菲波拉契数列问题

public class lianxi01 {

public static void main(String[] args) {

System、out、println("第1个月的兔子对数:    1");

System、out、println("第2个月的兔子对数:    1");

int f1 = 1, f2 = 1, f, M=24;

 for(int i=3; i<=M; i++) {

  f = f2;

  f2 = f1 + f2;

  f1 = f;

  System、out、println("第" + i +"个月的兔子对数: "+f2);

     }

}

}

。程序2。

题目:判断101-200之间有多少个素数,并输出所有素数。

程序分析:判断素数的方法:用1个数分别去除2到sqrt(这个数),如果能被整除, 则表明此数不是素数,反之是素数。

public class lianxi02 {

public static void main(String[] args) {

int count = 0;

for(int i=101; i<200; i+=2) {

 boolean b = false;

 for(int j=2; j<=Math、sqrt(i); j++)

 {

    if(i % j == 0) { b = false; break; }

     else    { b = true; }

 }

    if(b == true) {count ++;System、out、println(i );}

          }

System、out、println( "素数个数是: " + count);

}

}

。程序3。

题目:打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指1个三位数,其各位数字立方和等于该数本身。示例:153是1个 "水仙花数 ",因为153=1的三次方+5的三次方+3的三次方。

public class lianxi03 {

public static void main(String[] args) {

 int b1, b2, b3;

 for(int m=101; m<1000; m++) {

  b3 = m / 100;

  b2 = m % 100 / 10;

  b1 = m %    10;

  if((b3*b3*b3 + b2*b2*b2 + b1*b1*b1) == m) {

  System、out、println(m+"是1个水仙花数"); }

 }

}

}

。程序4。

题目:将1个正整数分解质因数。示例:输入90,打印出90=2*3*3*5。

程序分析:对n进行分解质因数,应先找到1个最小的质数k,然后按下述步骤完成:

(1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。

(2)如果n <> k,但n能被k整除,则应打印出k的值,并用n除以k的商,作为新的正整数你n,重复执行第1步。

(3)如果n不能被k整除,则用k+1作为k的值,重复执行第1步。

import java、util、*;

public class lianxi04{

public static void main(String[] args) {

    Scanner s = new Scanner(System、in);

    System、out、print( "请键入1个正整数: ");

    int    n    = s、nextInt();

    int k=2;

    System、out、print(n + "=" );

    while(k <= n) {

  if(k == n) {System、out、println(n);break;}

    else if( n % k == 0) {System、out、print(k + "*");n = n / k; }

    else    k++;

       }

 }

}

。程序5。

题目:利用条件运算符的嵌套来完成此题:学习成绩> =90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示。

import java、util、*;

public class lianxi05 {

public static void main(String[] args) {

 int x;

 char grade;

 Scanner s = new Scanner(System、in);

 System、out、print( "请输入1个成绩: ");

 x = s、nextInt();

 grade = x >= 90 ? 'A'

   : x >= 60 ? 'B'

   :'C';

System、out、println("等级为:"+grade);

}

}

。程序6。

题目:输入两个正整数m和n,求其最大公约数和最小公倍数。

/**在循环中,只要除数不等于0,用较大数除以较小的数,将小的1个数作为下1轮循环的大数,取得的余数作为下1轮循环的较小的数,如此循环直到较小的数的值为0,返回较大的数,此数即为最大公约数,最小公倍数为两数之积除以最大公约数。* /

import java、util、*;

public    class lianxi06 {

public static void main(String[] args) {

int a ,b,m;

Scanner s = new Scanner(System、in);

System、out、print( "键入1个整数: ");

a = s、nextInt();

System、out、print( "再键入1个整数: ");

b = s、nextInt();

  deff cd = new deff();

  m = cd、deff(a,b);

  int n = a * b / m;

  System、out、println("最大公约数: " + m);

  System、out、println("最小公倍数: " + n);

}

}

class deff{

public int deff(int x, int y) {

 int t;

 if(x < y) {

  t = x;

  x = y;

  y = t;

 }

 while(y != 0) {

  if(x == y) return x;

  else {

   int k = x % y;

   x = y;

   y = k;

  }

 }

 return x;

}

}

。程序7。

题目:输入1行字符,分别统计出其中英文字母、空格、数字和其它字符的个数。

package WuYang;

import java、util、*;

public class lianxi07 {

public static void main(String[] args) {

int abcCount=0;//英文字母个数

int spaceCount=0;//空格键个数

int numCount=0;//数字个数

int otherCount=0;//其他字符个数

Scanner scan = new Scanner(System、in);//扫描器接受控制台的输入信息

System、out、println("输入1组字符");

String str=scan、nextLine();//取出控制台的1行信息,也就是你输入的信息

char[] ch = str、toCharArray();//将取道的string变成1个char数组

 for(int i=0;i<ch、length;i++){

  if(Character、isLetter(ch[i])){

   //判断是否字母

   abcCount++;

  }

  else if(Character、isDigit(ch[i])){

   //判断是否数字

   numCount++;

  }

  else if(Character、isSpaceChar(ch[i])){

   //判断是否空格键

   spaceCount++;

  }

  else{

   //以上都不是则认为是其他字符

   otherCount++;

  }

 }

 System、out、println("字母个数:"+abcCount);

 System、out、println("数字个数:"+numCount);

 System、out、println("空格个数:"+spaceCount);

 System、out、println("其他字符个数:"+otherCount);

}

}

。程序8。

题目:求s=a+aa+aaa+aaaa+aa、、、a的值,其中a是1个数字。示例2+22+222+2222+22222(此时共有5个数相加),几个数相加有键盘控制。

import java、util、*;

public class lianxi08 {

public static void main(String[] args) {

 long a , b = 0, sum = 0;

 Scanner s = new Scanner(System、in);

 System、out、print("输入数字a的值: ");

 a = s、nextInt();

 System、out、print("输入相加的项数:");

 int n = s、nextInt();

 int i = 0;

 while(i < n) {

  b = b + a;

  sum = sum + b;

  a = a * 10;

  ++ i;

 }

  System、out、println(sum);

}

}

。程序9。

题目:1个数如果恰好等于它的因子之和,这个数就称为 "完数 "。示例6=1+2+3、编程 找出1000以内的所有完数。

public class lianxi09 {

public static void main(String[] args) {

 System、out、println("1到1000的完数有: ");

 for(int i=1; i<1000; i++) {

  int t = 0;

  for(int j=1; j<= i/2; j++) {

   if(i % j == 0) {

    t = t + j;

   }

  }

  if(t == i) {

   System、out、print(i + " ");

  }

 }

}

}

。程序10。

题目:1球从100米高度自由落下,每次落地后反跳回原高度的1半;再落下,求它在 第10次落地时,共经过多少米?第10次反弹多高?

public class lianxi10 {

public static void main(String[] args) {

  double h = 100,s = 0;

  for(int i=1; i<=10; i++) {

  s = s + 2*h;

  h = h / 2;

 }

  s=s-100;

 System、out、println("经过路程:" + s);

 System、out、println("最后高度:" + h);

}

}

。程序11。

题目:有1、2、3、4四个数字,能组成多少个互不相同且1个数字中无重复数字的三位数?并将他们都输入。

public class lianxi11 {

public static void main(String[] args) {

 int count = 0;

 for(int x=1; x<5; x++) {

  for(int y=1; y<5; y++) {

   for(int z=1; z<5; z++) {

    if(x != y && y != z && x != z) {

     count ++;

     System、out、println(x*100 + y*10 + z );

    }

   }

  }

 }

 System、out、println("共有" + count + "个三位数");

}

}

。程序12。

题目:企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可可提成7、5%;20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1、5%,高于100万元时,超过100万元的部分按1%提成,从键盘输入当月利润,求应发放奖金总数?

import java、util、*;

public class lianxi12 {

public static void main(String[] args) {

 double x = 0,y = 0;

 System、out、print("输入当月利润(万):");

 Scanner s = new Scanner(System、in);

 x = s、nextInt();

 if(x > 0 && x <= 10) {

 y = x * 0、1;

 } else if(x > 10 && x <= 20) {

  y = 10 * 0、1 + (x - 10) * 0、075;

 } else if(x > 20 && x <= 40) {

  y = 10 * 0、1 + 10 * 0、075 + (x - 20) * 0、05;

 } else if(x > 40 && x <= 60) {

  y = 10 * 0、1 + 10 * 0、075 + 20 * 0、05 + (x - 40) * 0、03;

 } else if(x > 60 && x <= 100) {

  y = 20 * 0、175 + 20 * 0、05 + 20 * 0、03 + (x - 60) * 0、015;

 } else if(x > 100) {

  y = 20 * 0、175 + 40 * 0、08 + 40 * 0、015 + (x - 100) * 0、01;

 }

 System、out、println("应该提取的奖金是 " + y + "万");

}

}

。程序13。

题目:1个整数,它加上100后是1个完全平方数,再加上168又是1个完全平方数,请问该数是多少?

public class lianxi13 {

public static void main(String[] args) {

 for(int x =1; x<100000; x++) {

  if(Math、sqrt(x+100) % 1 == 0) {

   if(Math、sqrt(x+168) % 1 == 0) {

    System、out、println(x + "加100是1个完全平方数,再加168又是1个完全平方数");

   }

  }

 }

}

}

/*按题意循环应该从-100开始(整数包括正整数、负整数、零),这样会多1个满足条件的数-99。

但是我看到大部分人解这道题目时都将题中的“整数”理解成正整数,我也就随大流了。*/

。程序14。

题目:输入某年某月某日,判断这1天是这1年的第几天?

import java、util、*;

public class lianxi14 {

public static void main(String[] args) {

 int year, month, day;

 int days = 0;

 int d = 0;

 int e;

 input fymd = new input();

 do {

 e = 0;

 System、out、print("输入年:");

 year =fymd、input();

 System、out、print("输入月:");

 month = fymd、input();

 System、out、print("输入天:");

 day = fymd、input();

 if (year < 0 || month < 0 || month > 12 || day < 0 || day > 31) {

 System、out、println("输入错误,请重新输入!");

 e=1 ;

 }

 }while( e==1);

  for (int i=1; i <month; i++) {

  switch (i) {

  case 1:

  case 3:

  case 5:

  case 7:

  case 8:

  case 10:

  case 12:

   days = 31;

  break;

  case 4:

  case 6:

  case 9:

  case 11:

   days = 30;

  break;

  case 2:

   if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) {

    days = 29;

   } else {

    days = 28;

   }

   break;

  }

  d += days;

  }

 System、out、println(year + "-" + month + "-" + day + "是这年的第" + (d+day) + "天。");

}

}

class input{

public int input() {

 int value = 0;

 Scanner s = new Scanner(System、in);

 value = s、nextInt();

 return value;

}

}

。程序15。

题目:输入三个整数x,y,z,请将这三个数由小到大输出。

import java、util、*;

public class lianxi15 {

public static void main(String[] args) {

 input fnc = new input();

 int x=0, y=0, z=0;

 System、out、print("输入第1个数字:");

  x = fnc、input();

 System、out、print("输入第2个数字:");

  y = fnc、input();

 System、out、print("输入第三个数字:");

  z = fnc、input();

if(x > y) {

  int t = x;

  x = y;

  y = t;

 }

if(x > z) {

  int t = x;

  x = z;

  z = t;

 }

if(y > z) {

  int t = y;

  y = z;

  z = t;

 }

System、out、println( "三个数字由小到大排列为: "+x + " " + y + " " + z);

}

}

class input{

public int input() {

 int value = 0;

 Scanner s = new Scanner(System、in);

 value = s、nextInt();

 return value;

}

}

。程序16。

题目:输出9*9口诀。 

public class lianxi16 {

public static void main(String[] args) {

 for(int i=1; i<10; i++) {

  for(int j=1; j<=i; j++) {

   System、out、print(j + "*" + i + "=" + j*i + "    " );

     if(j*i<10){System、out、print(" ");}

}

  System、out、println();

 }

}

}

。程序17。

题目:猴子吃桃问题:猴子第1天摘下若干个桃子,当即吃了1半,还不瘾,又多吃了1个 第2天早上又将剩下的桃子吃掉1半,又多吃了1个。以后每天早上都吃了前1天剩下 的1半零1个。到第10天早上想再吃时,见只剩下1个桃子了。求第1天共摘了多少。

public class lianxi17 {

public static void main(String[] args) {

 int x = 1;

 for(int i=2; i<=10; i++) {

  x = (x+1)*2;

 }

 System、out、println("猴子第1天摘了 " + x + " 个桃子");

}

}

。程序18。

题目:两个乒乓球队进行比赛,各出三人。甲队为a,b,c三人,乙队为x,y,z三人。已抽签决定比赛名单。有人向队员打听比赛的名单。a说他不和x比,c说他不和x,z比,请编程序找出三队赛手的名单。

public class lianxi18 {

static char[] m = { 'a', 'b', 'c' };

static char[] n = { 'x', 'y', 'z' };

public static void main(String[] args) {

for (int i = 0; i < m、length; i++) {

for (int j = 0; j < n、length; j++) {

 if (m[i] == 'a' && n[j] == 'x') {

  continue;

} else if (m[i] == 'a' && n[j] == 'y') {

  continue;

 } else if ((m[i] == 'c' && n[j] == 'x')

   || (m[i] == 'c' && n[j] == 'z')) {

  continue;

 } else if ((m[i] == 'b' && n[j] == 'z')

   || (m[i] == 'b' && n[j] == 'y')) {

  continue;

 } else

  System、out、println(m[i] + " vs " + n[j]);

}

}

}

}

。程序19。

题目:打印出如下图案(菱形)

 *

***

*****

*******

*****

***

*

public class lianxi19 {

public static void main(String[] args) {

int H = 7, W = 7;//高和宽必须是相等的奇数

for(int i=0; i<(H+1) / 2; i++) {

 for(int j=0; j<W/2-i; j++) {

  System、out、print(" ");

 }

 for(int k=1; k<(i+1)*2; k++) {

  System、out、print('*');

 }

 System、out、println();

}

for(int i=1; i<=H/2; i++) {

 for(int j=1; j<=i; j++) {

  System、out、print(" ");

 }

 for(int k=1; k<=W-2*i; k++) {

  System、out、print('*');

 }

 System、out、println();

}

}

}

。程序20。

题目:有1分数序列:2/1,3/2,5/3,8/5,13/8,21/13、、、求出这个数列的前20项之和。

public class lianxi20 {

public static void main(String[] args) {

int x = 2, y = 1, t;

double sum = 0;

for(int i=1; i<=20; i++) {

 sum = sum + (double)x / y;

 t = y;

 y = x;

 x = y + t;

 }

System、out、println("前20项相加之和是: " + sum);

}

}

。程序21。

题目:求1+2!+3!+、、、+20!的和

public class lianxi21 {

public static void main(String[] args) {

long sum = 0;

long fac = 1;

for(int i=1; i<=20; i++) {

 fac = fac * i;

 sum += fac;

}

System、out、println(sum);

}

}

。程序22。

题目:利用递归方法求5!。

public class lianxi22 {

public static void main(String[] args) {

   int n = 5;

rec fr = new rec();

System、out、println(n+"! = "+fr、rec(n));

}

}

class rec{

public long rec(int n) {

long value = 0 ;

if(n ==1 ) {

 value = 1;

} else   {

 value = n * rec(n-1);

}

return value;

}

}

。程序23。

题目:有5个人坐在1起,问第五个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第三个人,又说比第2人大两岁。问第2个人,说比第1个人大两岁。最后问第1个人,他说是10岁。请问第五个人多大?

public class lianxi23 {

public static void main(String[] args) {

int age = 10;

 for(int i=2; i<=5; i++) {

 age =age+2;

}

System、out、println(age);

}

}

。程序24。

题目:给1个不多于5位的正整数,要求:1、求它是几位数,二、逆序打印出各位数字。

//使用了长整型最多输入18位

import java、util、*;

public class lianxi24 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、print("请输入1个正整数:");

long a = s、nextLong();

String ss = Long、toString(a);

char[] ch = ss、toCharArray();

int j=ch、length;

System、out、println(a + "是1个"+ j +"位数。");

System、out、print("按逆序输出是:");

for(int i=j-1; i>=0; i--) {

System、out、print(ch[i]);

}

}

}

。程序25。

题目:1个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。

import java、util、*;

public class lianxi25 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int a;

do{

 System、out、print("请输入1个5位正整数:");

  a = s、nextInt();

  }while(a<10000||a>99999);

 String ss =String、valueOf(a);

 char[] ch = ss、toCharArray();

 if(ch[0]==ch[4]&&ch[1]==ch[3]){

 System、out、println("这是1个回文数");}

 else {System、out、println("这不是1个回文数");}

}

}

//这个更好,不限位数

import java、util、*;

public class lianxi25a {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

boolean is =true;

System、out、print("请输入1个正整数:");

long a = s、nextLong();

String ss = Long、toString(a);

char[] ch = ss、toCharArray();

int j=ch、length;

for(int i=0; i<j/2; i++) {

if(ch[i]!=ch[j-i-1]){is=false;}

}

if(is==true){System、out、println("这是1个回文数");}

 else {System、out、println("这不是1个回文数");}

}

}

。程序26。

题目:请输入星期几的第1个字母来判断1下是星期几,如果第1个字母1样,则继续   判断第2个字母。

import java、util、*;

public class lianxi26 {

public static void main(String[] args) {

getChar tw = new getChar();

System、out、println("请输入星期的第1个大写字母:");

char ch = tw、getChar();

switch(ch) {

 case 'M':

  System、out、println("Monday");

  break;

 case 'W':

  System、out、println("Wednesday");

  break;

 case 'F':

  System、out、println("Friday");

  break;

 case 'T': {

  System、out、println("请输入星期的第2个字母:");

  char ch2 = tw、getChar();

  if(ch2 == 'U') {System、out、println("Tuesday"); }

  else if(ch2 == 'H') {System、out、println("Thursday"); }

  else {System、out、println("无此写法!");

   }

 };

  break;

 case 'S': {

   System、out、println("请输入星期的第2个字母:");

  char ch2 = tw、getChar();

  if(ch2 == 'U') {System、out、println("Sunday"); }

   else if(ch2 == 'A') {System、out、println("Saturday"); }

   else {System、out、println("无此写法!");

   }

 };

  break;

default:System、out、println("无此写法!");

}

}

}

class getChar{

public char getChar() {

Scanner s = new Scanner(System、in);

String str = s、nextLine();

char ch = str、charAt(0);

if(ch<'A' || ch>'Z') {

 System、out、println("输入错误,请重新输入");

 ch=getChar();

}

return ch;

}

}

。程序27。

题目:求100之内的素数

//使用除sqrt(n)的方法求出的素数不包括2和3

public class lianxi27 {

public static void main(String[] args) {

boolean b =false;

System、out、print(2 + " ");

System、out、print(3 + " ");

for(int i=3; i<100; i+=2) {

 for(int j=2; j<=Math、sqrt(i); j++) {

  if(i % j == 0) {b = false;

      break;

   } else{b = true;}

 }

if(b == true) {System、out、print(i + " ");}

}

}

}

//该程序使用除1位素数得2位方法,运行效率高通用性差。

public class lianxi27a {

public static void main(String[] args) {

int[] a = new int[]{2, 3, 5, 7};

for(int j=0; j<4; j++)System、out、print(a[j] + " ");

boolean b =false;

for(int i=11; i<100; i+=2) {

 for(int j=0; j<4; j++) {

  if(i % a[j] == 0) {b = false;

      break;

   } else{b = true;}

 }

if(b == true) {System、out、print(i + " ");}

}

}

}

。程序28。

题目:对10个数进行排序

import java、util、*;

public class lianxi28 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int[] a = new int[10];

System、out、println("请输入10个整数:");

for(int i=0; i<10; i++) {

a[i] = s、nextInt();

}

for(int i=0; i<10; i++) {

for(int j=i+1; j<10; j++) {

if(a[i] > a[j]) {

int t = a[i];

a[i] = a[j];

a[j] = t;

}

}

}

for(int i=0; i<10; i++) {

System、out、print(a[i] + " ");

}

}

}

。程序29。

题目:求1个3*3矩阵对角线元素之和

import java、util、*;

public class lianxi29 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int[][] a = new int[3][3];

System、out、println("请输入9个整数:");

for(int i=0; i<3; i++) {

for(int j=0; j<3; j++) {

 a[i][j] = s、nextInt();

}

}

System、out、println("输入的3 * 3 矩阵是:");

for(int i=0; i<3; i++) {

for(int j=0; j<3; j++) {

 System、out、print(a[i][j] + " ");

}

System、out、println();

}

int sum = 0;

for(int i=0; i<3; i++) {

for(int j=0; j<3; j++) {

 if(i == j) {

  sum += a[i][j];

 }

}

}

System、out、println("对角线之和是:" + sum);

}

}

。程序30。

题目:有1个已经排好序的数组。现输入1个数,要求按原来的规律将它插入数组中。

//此程序不好,没有使用折半查找插入

import java、util、*;

public class lianxi30 {

public static void main(String[] args) {

int[] a = new int[]{1, 2, 6, 14, 25, 36, 37,55};

int[] b = new int[a、length+1];

int t1=0, t2 = 0;        

int i =0;

Scanner s= new Scanner(System、in);

System、out、print("请输入1个整数:");

int num = s、nextInt();

if(num >= a[a、length-1]) {

b[b、length-1] = num;

for(i=0; i<a、length; i++) {

 b[i] = a[i];

}

} else {

for(i=0; i<a、length; i++) {

 if(num >= a[i]) {

  b[i] = a[i];

 } else { 

  b[i] = num;

  break;

 }

}

for(int j=i+1; j<b、length; j++) {

 b[j] = a[j-1];

}

}

for (i = 0; i < b、length; i++) {

System、out、print(b[i] + " ");

}

}       

}

。程序31。

题目:将1个数组逆序输出。

import java、util、*;

public class lianxi31 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int a[] = new int[20];

System、out、println("请输入多个正整数(输入-1表示结束):");

int i=0,j;

do{

  a[i]=s、nextInt();

  i++;

}while (a[i-1]!=-1);

System、out、println("你输入的数组为:");

for( j=0; j<i-1; j++) {

System、out、print(a[j]+"   ");

}

System、out、println("\n数组逆序输出为:");

for( j=i-2; j>=0; j=j-1) {

System、out、print(a[j]+"   ");

}

}

}

。程序32。

题目:取1个整数a从右端开始的4~7位。

import java、util、*;

public class lianxi32 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、print("请输入1个7位以上的正整数:");

long a = s、nextLong();

String ss = Long、toString(a);

char[] ch = ss、toCharArray();

int j=ch、length;

if (j<7){System、out、println("输入错误!");}

else {

 System、out、println("截取从右端开始的4~7位是:"+ch[j-7]+ch[j-6]+ch[j-5]+ch[j-4]);

 }

}

}

。程序33。

题目:打印出杨辉三角形(要求打印出10行如下图) 

    1

  1    1

    1    2    1

  1    3    3    1

1    4    6    4    1

1    5    10    10    5    1

…………

public class lianxi33 {

public static void main(String[] args) {

int[][] a = new int[10][10];

for(int i=0; i<10; i++) {

a[i][i] = 1;

a[i][0] = 1;

}

for(int i=2; i<10; i++) {

for(int j=1; j<i; j++) {

 a[i][j] = a[i-1][j-1] + a[i-1][j];

}

}

 for(int i=0; i<10; i++) {

for(int k=0; k<2*(10-i) 1; k++) {

 System、out、print(" ");

}

for(int j=0; j<=i; j++) {

 System、out、print(a[i][j] + "   ");

}

System、out、println();

}

}

}

。程序34。

题目:输入3个数a,b,c,按大小顺序输出。

import java、util、Scanner;

public class lianxi34 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、println("请输入3个整数:");

int a = s、nextInt();

int b = s、nextInt();

int c = s、nextInt();

  if(a < b) {

 int t = a;

 a = b;

 b = t;

}

  if(a < c) {

 int t = a;

 a = c;

 c = t;

}

 if(b < c) {

 int t = b;

 b = c;

 c = t;

}

System、out、println("从大到小的顺序输出:");

System、out、println(a + " " + b + " " + c);

}

}

。程序35。

题目:输入数组,最大的与第1个元素交换,最小的与最后1个元素交换,输出数组。

import java、util、*;

public class lianxi35 {

public static void main(String[] args) {

int N = 8;

int[] a = new int[N];// 创建1个八个元素的数组

Scanner s = new Scanner(System、in);

int idx1 = 0, idx2 = 0;

System、out、println("请输入8个整数:");

for (int i = 0; i < N; i++) {

a[i] = s、nextInt();

}

// 获得输入的八个数字

System、out、println("你输入的数组为:");

for (int i = 0; i < N; i++) {

System、out、print(a[i] + " ");

}

// 输出输入的数组

int max = a[0], min = a[0];

for (int i = 0; i < N; i++) {

if (a[i] > max) {

max = a[i];

idx1 = i;

}

// 找出最大的数和其下标

if (a[i] < min) {

min = a[i];

idx2 = i;

}// 找出最大的数和其下标

}

if (idx1 != 0) {

int temp = a[0];

a[0] = a[idx1];

a[idx1] = temp;

}// 最大的数和第1个数交换位置

if (idx2 != N - 1) {

int temp = a[N - 1];

a[N - 1] = a[idx2];

a[idx2] = temp;

}// 最小的数和最后1个数交换位置

System、out、println("\n交换后的数组为:");

for (int i = 0; i < N; i++) {

System、out、print(a[i] + " ");

}

}

}

。程序36。

题目:有n个整数,使其前面各数顺序向后移m个位置,最后m个数变成最前面的m个数

import java、util、Scanner;

public class lianxi36 {

public static void main(String[] args) {

int N =10;

int[] a = new int[N];

Scanner s = new Scanner(System、in);

System、out、println("请输入10个整数:");

for(int i=0; i<N; i++) {

a[i] = s、nextInt();

}

System、out、print("你输入的数组为:");

for(int i=0; i<N; i++) {

 System、out、print(a[i] + " ");

}

System、out、print("\n请输入向后移动的位数:");

int m = s、nextInt();

int[] b = new int[m];

for(int i=0; i<m; i++) {

b[i] = a[N-m+i];

}

for(int i=N-1; i>=m; i--) {

a[i] = a[i-m];

}

for(int i=0; i<m; i++) {

a[i] = b[i];

}

System、out、print("位移后的数组是:");

for(int i=0; i<N; i++) {

System、out、print(a[i] + " ");

}

}

}

。程序37。

题目:有n个人围成1圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。

import java、util、Scanner;

public class lianxi37 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、print("请输入排成1圈的人数:");

int n = s、nextInt();

boolean[] arr = new boolean[n];

for(int i=0; i<arr、length; i++) {

arr[i] = true;

}//数组赋值都是true

int leftCount = n;

int countNum = 0;

int index = 0;

while(leftCount > 1) {

if(arr[index] == true) {

 countNum ++;

 if(countNum == 3) {

  countNum =0;

  arr[index] = false;

  leftCount --;

 }

}

 index ++;

 if(index == n) {

index = 0;

}

}

for(int i=0; i<n; i++) {

if(arr[i] == true) {

 System、out、println("原排在第"+(i+1)+"位的人留下了。");

}

}

}

}

。程序38。

题目:写1个函数,求1个string的长度,在main函数中输入string,并输出其长度。

/*………………

*……题目意思似乎不能用length()函数 */

import java、util、*;

public class lianxi38 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、println("请输入1个string:");

String str = s、nextLine();

 System、out、println("string的长度是:"+str、length());

}

}

。程序39。

题目:编写1个函数,输入n为偶数时,调用函数求1/2+1/4+、、、+1/n,当输入n为奇数时,调用函数1/1+1/3+、、、+1/n(利用指针函数)

//没有利用指针函数

import java、util、*;

public class lianxi39 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、print("请输入1个正整数 n= ");

int n = s、nextInt();

System、out、println("相应数列的和为:" + sum(n));

}

public static double sum(int n) {

double res = 0;

if(n % 2 == 0) {

 for(int i=2; i<=n; i+=2) {

  res += (double)1 / i;

 }

} else {

 for(int i=1; i<=n; i+=2) {

  res += (double)1 / i ;

 }

}

return res;

}

}

。程序40。

题目:string排序。

public class lianxi40 {

public static void main(String[] args) {

int N=5;

String temp = null;

String[] s = new String[N];

s[0] = "matter";

s[1] = "state";

s[2] = "solid";

s[3] = "liquid";

s[4] = "gas";

for(int i=0; i<N; i++) {

for(int j=i+1; j<N; j++) {

 if(compare(s[i], s[j]) == false) {

  temp = s[i];

  s[i] = s[j];

  s[j] = temp;

 }

}

}

for(int i=0; i<N; i++) {

System、out、println(s[i]);

}

}

static boolean compare(String s1, String s2) {

boolean result = true;

for(int i=0; i<s1、length() && i<s2、length(); i++) {

if(s1、charAt(i) > s2、charAt(i)) {

 result = false;

 break;

} else if(s1、charAt(i) <s2、charAt(i)) {

 result = true;

 break;

} else {

 if(s1、length() < s2、length()) {

  result = true;

 } else {

  result = false;

 }

}

}

return result;

}

}

。程序41。

题目:海滩上有1堆桃子,五只猴子来分。第1只猴子将这堆桃子凭据分为五份,多了1个,这只猴子将多的1个扔入海中,拿走了1份。第2只猴子将剩下的桃子又平均分成五份,又多了1个,它同样将多的1个扔入海中,拿走了1份,第三、第四、第五只猴子都是这样做的,问海滩上原来最少有多少个桃子?

public class lianxi41 {

public static void main (String[] args) {

int i,m,j=0,k,count;

for(i=4;i<10000;i+=4)

{ count=0;

 m=i;

 for(k=0;k<5;k++)

    {

     j=i/4*5+1;

     i=j;

     if(j%4==0)

    count++;

    else break;

   }

i=m;

if(count==4)

{System、out、println("原有桃子 "+j+" 个");

break;}

}

}

}

。程序42。

题目:809*??=800*??+9*??+1    其中??代表的两位数,8*??的结果为两位数,9*??的结果为3位数。求??代表的两位数,及809*??后的结果。

//题目错了!809x=800x+9x+1 这样的方程无解。去掉那个1就有解了。

public class lianxi42 {

public static void main (String[] args) {

int a=809,b,i;

for(i=10;i<13;i++)

{b=i*a ;

if(8*i<100&&9*i>=100)

System、out、println ("809*"+i+"="+"800*"+i+"+"+"9*"+i+"="+b);}

}

}

。程序43。

题目:求0—7所能组成的奇数个数。

//组成1位数是4个。

//组成2位数是7*4个。

//组成3位数是7*8*4个。

//组成4位数是7*8*8*4个。

//、、、、、、

public class lianxi43 {

public static void main (String[] args) {

int sum=4;

int j;

System、out、println("组成1位数是 "+sum+" 个");

sum=sum*7;

System、out、println("组成2位数是 "+sum+" 个");

for(j=3;j<=9;j++){

sum=sum*8;

System、out、println("组成"+j+"位数是 "+sum+" 个");

}

}

}

。程序44。

题目:1个偶数总能表示为两个素数之和。

//由于用除sqrt(n)的方法求出的素数不包括2和3,

//因此在判断是否是素数程序中人为添加了1个3。

import java、util、*;

public class lianxi44 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int n,i;

do{

 System、out、print("请输入1个大于等于6的偶数:");

 n = s、nextInt();

} while(n<6||n%2!=0);   //判断输入是否是>=6偶数,不是,重新输入

fun fc = new fun();

for(i=2;i<=n/2;i++){

if((fc、fun(i))==1&&(fc、fun(n-i)==1))

{int j=n-i;

 System、out、println(n+" = "+i+" + "+j);

 } //输出所有可能的素数对

}

}

}

class fun{

public int fun (int a)    //判断是否是素数的函数

{

int i,flag=0;

if(a==3){flag=1;return(flag);}

for(i=2;i<=Math、sqrt(a);i++){

if(a%i==0) {flag=0;break;}

  else flag=1;}

return (flag) ;//不是素数,返回0,是素数,返回1

}

}

//解法二

import java、util、*;

public class lianxi44 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int n;

do{

 System、out、print("请输入1个大于等于6的偶数:");

 n = s、nextInt();

} while(n<6||n%2!=0);   //判断输入是否是>=6偶数,不是,重新输入

for(int i=3;i<=n/2;i+=2){

if(fun(i)&&fun(n-i)) {

  System、out、println(n+" = "+i+" + "+(n-i));

  } //输出所有可能的素数对

}

}

static boolean fun (int a){    //判断是否是素数的函数

boolean flag=false;

if(a==3){flag=true;return(flag);}

for(int i=2;i<=Math、sqrt(a);i++){

if(a%i==0) {flag=false;break;}

  else flag=true;}

return (flag) ;

}

}

。程序45。

题目:判断1个素数能被几个9整除

//题目错了吧?能被9整除的就不是素数了!所以改成整数了。

import java、util、*;

public class lianxi45 {

public static void main (String[] args) {

Scanner s = new Scanner(System、in);

System、out、print("请输入1个整数:");

int num = s、nextInt();

int   tmp = num;

int count = 0;

   for(int i = 0 ; tmp%9 == 0 ;){

   tmp = tmp/9;

    count ++;

  }

 System、out、println(num+" 能够被 "+count+" 个9整除。");

 }

}

。程序46。

题目:两个string连接程序

import java、util、*;

public class lianxi46 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

System、out、print("请输入1个string:");

String str1 = s、nextLine();

System、out、print("请再输入1个string:");

String str2 = s、nextLine();

String str = str1+str2;

System、out、println("连接后的string是:"+str);

}

}

。程序47。

题目:读取7个数(1—50)的整数值,每读取1个值,程序打印出该值个数的*。

import java、util、*;

public class lianxi47 {

public static void main(String[] args) {

Scanner s = new Scanner(System、in);

int n=1,num;

while(n<=7){

     do{

  System、out、print("请输入1个1--50之间的整数:");

     num= s、nextInt();

   }while(num<1||num>50);

  for(int i=1;i<=num;i++)

  {System、out、print("*");

  }

System、out、println();

n ++;

}

}

}

。程序48。

题目:某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密要求如下:每位数字都加上5,然后用和除以10的余数代替该数字,再将第1位和第四位交换,第2位和第三位交换。

import java、util、*;

public class lianxi48   {

public static void main(String args[]) {

Scanner s = new Scanner(System、in);

int num=0,temp;

do{

System、out、print("请输入1个4位正整数:");

  num = s、nextInt();

 }while (num<1000||num>9999);

int a[]=new int[4];

a[0] = num/1000; //取千位的数字

a[1] = (num/100)%10; //取百位的数字

a[2] = (num/10)%10; //取十位的数字

a[3] = num%10; //取个位的数字

for(int j=0;j<4;j++)

{

a[j]+=5;

a[j]%=10;

}

for(int j=0;j<=1;j++)

{

temp = a[j];

a[j] = a[3-j];

a[3-j] =temp;

}

System、out、print("加密后的数字为:");

for(int j=0;j<4;j++)

System、out、print(a[j]);

}

}

。程序49。

题目:计算string中子串出现的次数

import java、util、*;

public class lianxi49 {

public static void main(String args[]){

Scanner s = new Scanner(System、in);

System、out、print("请输入string:");

String str1 = s、nextLine();

System、out、print("请输入子串:");

String str2 = s、nextLine();

int count=0;

if(str1、equals("")||str2、equals(""))

{

System、out、println("你没有输入string或子串,无法比较!");

System、exit(0);

}

else

{

for(int i=0;i<=str1、length() str2、length();i++)

 {

 if(str2、equals(str1、substring(i, str2、length()+i)))

  //这种比法有问题,会将"aaa"看成有2个"aa"子串。

   count++;

   }

System、out、println("子串在string中出现: "+count+" 次");

}

}

}

。程序50。

题目:有五个学生,每个学生有3门课的成绩,从键盘输入以上数据(包括学生号,姓名,三门课成绩),计算出平均成绩,将原有的数据和计算出的平均分数存放在磁盘文件 "stud "中。

import java、io、*;

import java、util、*;

public class lianxi50 {

public static void main(String[] args){

Scanner ss = new Scanner(System、in);

String [][] a = new String[5][6];

for(int i=1; i<6; i++) {

System、out、print("请输入第"+i+"个学生的学号:");

a[i-1][0] = ss、nextLine();

System、out、print("请输入第"+i+"个学生的姓名:");

a[i-1][1] = ss、nextLine();

for(int j=1; j<4; j++) {

   System、out、print("请输入该学生的第"+j+"个成绩:");

   a[i-1][j+1] = ss、nextLine();

   }

System、out、println("\n");

}

//以下计算平均分

float avg;

int sum;

for(int i=0; i<5; i++) {

sum=0;

for(int j=2; j<5; j++) {

sum=sum+ Integer、parseInt(a[i][j]);

  }

avg= (float)sum/3;

a[i][5]=String、valueOf(avg);

}

//以下写磁盘文件

String s1;

try {

File f = new File("C:\\stud");

if(f、exists()){

  System、out、println("文件存在");

  }else{

     System、out、println("文件不存在,正在创建文件");

  f、createNewFile();//不存在则创建

    }

BufferedWriter output = new BufferedWriter(new FileWriter(f));

for(int i=0; i<5; i++) {

for(int j=0; j<6; j++) {

s1=a[i][j]+"\r\n";

output、write(s1);

}

}

output、close();

System、out、println("数据已写入c盘文件stud中!");

} catch (Exception e) {

 e、printStackTrace();

 }

}

}

自己写的程序:

1、 判断1个数是否为素数

public class lianxi33 {

public static void main(String[] args) {

for (int i = 1; i <=10000; i++) {

int n = i;

if (isPrime(n)) {

System、out、println(i + "是素数");

}

}

}

// 输入1个数判断其是否为素数

public static boolean isPrime(int n) {

if (n <= 1) {

return false;

}

if (n == 2) {

return true;

}

if (n % 2 == 0) {

return false;

}

for (int i = 3; i <= (int) (Math、floor(Math、sqrt(n))) + 1; i = i + 2) {

if (n % i == 0) {

return false;

}

}

return true;

}

}

2、二分法查找

public class BinarySearch {

public static int binarySearch(int[] a, int x) {

// 在a[0]<=a[1]<=、、、<=a[n-1]中搜索x

// 找到x则返回x的所在位置,否则返回-1

int left = 0;

int right = a、length - 1;

while (left <= right) {

int middle = (left + right) / 2;

if (x == a[middle])

return middle;

if (x > a[middle])

left = middle + 1;

else

right = middle - 1;

}

return -1;

}

public static void main(String[] args) {

int[] a = { 0, 1, 3, 6, 7, 10, 21, 34, 36, 40, 76 };

int x = 34;// 设定要查找的数

int position = binarySearch(a, x);

System、out、println(x + "在数组中的位置是" + position);

}

}

2、 比较器 二分查找

import java、util、TreeSet;

import java、util、Iterator;

public class Student implements Comparable<Student> {

    private int id;

    private String name;

    private String dengji;

    public Student (int id, String name, String dengji) {

    this、id = id;

    this、name = name;

    this、dengji=dengji;

    }

    public void setId (int id) {

    this、id = id;

    }

    public void setName (String name) {

    this、name = name;

    }

    public void setDengji (String dengji) {

    this、dengji = dengji;

}

    public int getId () {

    return id;

    }

    public String getName () {

    return name;

    }

    public String getdengji () {

    return dengji;

}

    /* Student 类的string表达式,形如:

     * 2   张三 */

    public String toString () {

    return (id + "\t" + name+"\t" + dengji);

    }

    /* 实现 Comparable 接口中的 compareTo 方法,

     * 通常大于时返回1个正数,小于时返回1个负数,

     * 等于时返回零,具体情况可以自行决定。

     *********************************************************

     * 这里我根据 id 号的大小进行了比较。由于 TreeSet

     * 会根据 compareTo 的结果来排序,因此输出结果

     * 应该是按照 id 号从小到大排序的。

     * 如果要根据姓名进行排序,只需对这个方法进行相应的修改。*/

    public int compareTo (Student arg) {

    if (id > arg、id)

        return 1;

    else if (id == arg、id)

        return 0;

    else

        return -1;

    }

    /* 以下为主方法,输出结果是:

     * 3 John

     * 5 Tom

     * 7 Alice

     * 9 David

     * 可以看到不同于输入顺序,

     * TreeSet 已经将其排序了。*/

    public static void main (String args[]) {

    TreeSet<Student> tset = new TreeSet<Student>();

    tset、add(new Student(5, "Tom" ,  "a"));

    tset、add(new Student(3, "John",  "b" ));

    tset、add(new Student(9, "David",  "c" ));

    tset、add(new Student(7, "Alice" , "d"));

    Iterator<Student> itor = tset、iterator();

    while (itor、hasNext()) {

        System、out、println(itor、next()、toString());

    }

    }

}

**************************************************************************************************************************************************************

BinarySearch

import java、util、Comparator;

public class BinarySearch {

public static <T extends Comparable<T>> int binarySearch(T[] a, T x,

Comparator<T> comparator) {

if (a == null) {

throw new IllegalArgumentException("被查找数组为null!");

} else if (x == null) {

throw new IllegalArgumentException("被查询元素为null!");

}

int left = 0;

int right = a、length - 1;

while (left <= right) {

int middle = (left + right) / 2;

if (comparator != null) {

if (comparator、compare(x, a[middle]) == 0)

return middle;

if (comparator、compare(x, a[middle]) > 0)

left = middle + 1;

else

right = middle - 1;

}

else { if(x、compareTo(a[middle])==0)

return middle;

if(x、compareTo(a[middle])>0)

left = middle + 1;

else right = middle - 1; }

}

return -1;

}

public static void main(String[] args) {

Student[] a = new Student[4];

a[0] = (new Student(3, "Tom"));

a[1] = (new Student(5, "John"));

a[2] = (new Student(7, "David"));

a[3] = (new Student(9, "Alice"));

Student x = new Student(7, "John");// 设定要查找的数

int position = binarySearch(a, x, new StudentComparator());

System、out、println(x + "在数组中的位置是" + position);

}

}

Student

import java、util、TreeSet;

import java、util、Iterator;

public class Student implements Comparable<Student> {

   private int id;

   private String name;

   public Student (int id, String name) {

   this、id = id;

   this、name = name;

   

   }

   public void setId (int id) {

   this、id = id;

   }

   public void setName (String name) {

   this、name = name;

   }

   public int getId () {

   return id;

   }

   public String getName () {

   return name;

   }

   /* Student 类的string表达式,形如:

    * 2   张三 */

   public String toString () {

   return (id + "\t" + name+"\t" );

   }

   /* 实现 Comparable 接口中的 compareTo 方法,

    * 通常大于时返回1个正数,小于时返回1个负数,

    * 等于时返回零,具体情况可以自行决定。

    *********************************************************

    * 这里我根据 id 号的大小进行了比较。由于 TreeSet

    * 会根据 compareTo 的结果来排序,因此输出结果

    * 应该是按照 id 号从小到大排序的。

    * 如果要根据姓名进行排序,只需对这个方法进行相应的修改。*/

   public int compareTo (Student arg) {

   if (id > arg、id)

       return 1;

   else if (id == arg、id)

       return 0;

   else

       return -1;

   }

   /* 以下为主方法,输出结果是:

    * 3 John

    * 5 Tom

    * 7 Alice

    * 9 David

    * 可以看到不同于输入顺序,

    * TreeSet 已经将其排序了。*/

   public static void main (String args[]) {

   TreeSet<Student> tset = new TreeSet<Student>();

   tset、add(new Student(5, "Tom" ));

   tset、add(new Student(3, "John"));

   tset、add(new Student(9, "David"));

   tset、add(new Student(7, "Alice"));

   Iterator<Student> itor = tset、iterator();

   while (itor、hasNext()) {

       System、out、println(itor、next()、toString());

   }

}

}

StudentComparator

import java、util、Comparator;

/**

* Student 比较器

*/

public class StudentComparator implements Comparator<Student>

{

@Override

public int compare(Student s1, Student s2)

{

if(s1、getId()>s2、getId())

return 1;

else if(s1、getId()==s2、getId())

return 0;

else

return -1;

}

}

package test1;

/**

* Title: Hello Java World

* Description: 简单的Java程序,只显示1个信息。

* filename: HelloWorld、java

*/

public class HelloWorld {

public static void main(String[] args) {

System、out、println("Hello Java World!");

}

}

package test2;

/**

* Title: Java语言流程演示

* Description: 演示Java中几种常用的流程控制操作

* Filename: flowDome、java

*/

public class flowDemo{

public static void main(String[] arges){

 int iPara1,iPara2,iEnd;

 if(arges、length!=3)

 {

   System、out、println("USE :java flowDome parameter1 parameter2 circle");

   System、out、println("parameter1 : 比较条件1,数字类型");

   System、out、println("parameter2 : 比较条件2,数字类型");

   System、out、println("circle :循环次数");

   System、out、println("ego:java flowDome 1 2 5");

   return;

 }else{

   iPara1 = Integer、parseInt(arges[0]);

   iPara2 = Integer、parseInt(arges[1]);

   iEnd = Integer、parseInt(arges[2]);

 }

 //if语句

 if(iPara2>iPara1)

 {

  System、out、println("if 条件满足!");

  System、out、println("第2个数比第1个数大!");

 }

 else

 {

  System、out、println("if 条件不满足!");

  System、out、println("第2个数比第1个数小!");

 }

 //for循环操作

 for(int i=0;i<iEnd;i++)

 {

   System、out、println("这是for 第"+i+"次循环");

 }

 //while循环操作

 int i=0;

 while(i<iEnd)

 {

  System、out、println("这是while 第"+i+"次循环");

  i++;

 }

 //do-while循环操作

 int j=0;

 do

 {

  System、out、println("这是do-while 第"+j+"次循环");

  j++;

 }while(j<iEnd);

}

}

package test3;

/**

* Title: 数组数据操作

* Description: 演示1维数组和多维数组的初始化和基本操作

* Filename: myArray、java

*/

public class  myArray{

//初始化数组变量

char[] cNum = {'1','2','3','4','5','6','7','8','9','0'};

char[] cStr = {'a','b','c','d','e','f','g','h',

      'i','j','k','l','m','n','o','p',

      'q','r','s','t','u','v','w','x','y','z'};

int[] iMonth = {31,28,31,30,31,30,31,31,30,31,30,31};

String[] sMail = {"@","、"};

/**

*<br>方法说明:校验电子邮件

*<br>输入参数:String sPara 被校验的电子邮件字符

*<br>返回类型:boolean 如果校验的格式符合电子邮件格式返回true;否则返回false

*/

public boolean isMail(String sPara){

for(int i=0;i<sMail、length;i++){

  if(sPara、indexOf(sMail[i])==-1)

    return false;  

}

return true;

}

/**

*<br>方法说明:判断是否是数字

*<br>输入参数:String sPara。 需要判断的string

*<br>返回类型:boolean。如果都是数字类型,返回true;否则返回false

*/

public boolean isNumber(String sPara){

 int iPLength = sPara、length();

 for(int i=0;i<iPLength;i++){

  char cTemp = sPara、charAt(i);

  boolean bTemp = false;

  for(int j=0;j<cNum、length;j++){

    if(cTemp==cNum[j]){

  bTemp = true;

  break;

    }

  }

  if(!bTemp) return false;

 }

return true;

}

/**

*<br>方法说明:判断是否都是英文字符

*<br>输入参数:String sPara。要检查的字符

*<br>返回类型:boolean。如果都是字符返回true;反之为false

*/

public boolean isString(String sPara){

 int iPLength = sPara、length();

 for(int i=0;i<iPLength;i++){

  char cTemp = sPara、charAt(i);

  boolean bTemp = false;

  for(int j=0;j<cStr、length;j++){

    if(cTemp==cStr[j]){

  bTemp = true;

  break;

    }

  }

  if(!bTemp) return false;

 }

return true;

}

/**

*<br>方法说明:判断是否是闰年

*<br>输入参数:int iPara。要判断的年份

*<br>返回类型:boolean。如果是闰年返回true,否则返回false

*/

public boolean chickDay(int iPara){

 return iPara%100==0&&iPara%4==0;

}

/**

*<br>方法说明:检查日期格式是否正确

*<br>输入参数:String sPara。要检查的日期字符

*<br>返回类型:int 0 日期格式正确,-1 月或这日不合要求, -2 年月日格式不正确

*/

public int chickData(String sPara){

@SuppressWarnings("unused")

boolean bTemp = false;

//所输入日期长度不正确

if(sPara、length()!=10) return -2;

//获取年

String sYear = sPara、substring(0,4);

//判断年是否为数字

if(!isNumber(sYear)) return -2;

//获取月份

String sMonth = sPara、substring(5,7); 2011 05 05

//判断月份是否为数字

if(!isNumber(sMonth)) return -2;

//获取日

String sDay = sPara、substring(8,10);

//判断日是否为数字

if(!isNumber(sDay)) return -2;

//将年、月、日转换为数字

int iYear = Integer、parseInt(sYear);

int iMon = Integer、parseInt(sMonth);

int iDay = Integer、parseInt(sDay);

if(iMon>12) return -1;

//闰年二月处理

if(iMon==2&&chickDay(iYear)){

  if(iDay>29) return 2;

}else{

  if(iDay>iMonth[iMon-1]) return -1;

}

return 0;

}

/**

*<br>方法说明:主方法,测试用

*<br>输入参数:

*<br>返回类型:

*/

public static void main(String[] arges){

 myArray mA = new myArray();

 //校验邮件地址

 boolean bMail = mA、isMail("tom@163、com");

 System、out、println("1 bMail is "+bMail);

 bMail = mA、isMail("tom@163com");

 System、out、println("2 bMail is "+bMail);

 //演示是否是数字

 boolean bIsNum = mA、isNumber("1234");

 System、out、println("1:bIsNum="+bIsNum);

 bIsNum = mA、isNumber("123r4");

 System、out、println("2:bIsNum="+bIsNum);

 //演示是否是英文字符

 boolean bIsStr = mA、isString("wer");

 System、out、println("1:bIsStr="+bIsStr);

 bIsStr = mA、isString("wer3");

 System、out、println("2:bIsStr="+bIsStr);

 //演示检查日期

 int iIsTime = mA、chickData("2003-12-98");

 System、out、println("1:iIsTime="+iIsTime);

 iIsTime = mA、chickData("2003-111-08");

 System、out、println("2:iIsTime="+iIsTime);

 iIsTime = mA、chickData("2003-10-08");

 System、out、println("3:iIsTime="+iIsTime);

 iIsTime = mA、chickData("2000-02-30");

 System、out、println("4:iIsTime="+iIsTime);

}

}

package test4;

import java、util、*;

/**

* Title: 矢量操作<

* Description: 演示1个矢量(Vector)的基本操作

* Filename: operateVector、java

*/

public class operateVector

{

/*

*<br>方法说明:生成1个4*4的二维Vector,供使用。

*<br>输入参数:

*<br>输出变量:Vector

*<br>其它说明:

*/

public Vector<Object> buildVector(){

   Vector<Object> vTemps = new Vector<Object>();

   for(int i=0;i<4;i++){

  Vector<Object> vTemp = new Vector<Object>();

  for (int j=0;j<4;j++){

    vTemp、addElement("Vector("+i+")("+j+")");

  }

  vTemps、addElement(vTemp);

   }

   return vTemps;

}

/*

*<br>方法说明:插入数据

*<br>输入参数:Vector vTemp 待插入的数据对象

*<br>输入参数:int iTemp 插入数据的位置

*<br>输入参数:Object oTemp 插入数据值

*<br>输出变量:Vector 结果

*<br>其它说明:如果插入位置超出实例实际的位置将返回null

*/

public Vector<Object> insert(Vector<Object> vTemp,int iTemp,Object oTemp){

    if(iTemp>vTemp、size()){

    print("数据超界!");

    return null;

    }else{

     vTemp、insertElementAt(oTemp,iTemp);

    }

    return vTemp;

}

/*

*<br>方法说明:移除数据

*<br>输入参数:Vector vTemp 待删除矢量对象

*<br>输入参数:int iTemp 删除数据的位置

*<br>输出变量:Vector

*<br>其它说明:如果删除超界的数据,将返回null

*/

public Vector<Object> delete(Vector<Object> vTemp,int iTemp){

    if(iTemp>vTemp、size()){

    print("数据超界!");

    return null;

    }else{

     vTemp、removeElementAt(iTemp);

    }

    return vTemp;

}

/*

*<br>方法说明:修改数据

*<br>输入参数:Vector vTemp 待修改矢量对象

*<br>输入参数:int iTemp 修改数据的位置

*<br>输入参数:Object oTemp 修改数据值

*<br>输出变量:Vector

*<br>其它说明:如果修改位置超界的数据,将返回null

*/

public Vector<Object> updata(Vector<Object> vTemp,int iTemp,Object oTemp){

    if(iTemp>vTemp、size()){

    print("数据超界!");

    return null;

    }else{

     vTemp、setElementAt(oTemp,iTemp);

    }

    return vTemp;

}

/*

*<br>方法说明:输出信息

*<br>输入参数:String sTemp 输出信息名称

*<br>输入参数:Object oTemp 输出信息值

*<br>返回变量:无

*/

public void print(String sTemp,Vector<Object> oTemp){

    System、out、println(sTemp+"数据:");

    this、print(oTemp);

}

/**

*<br>方法说明:打印输出(过载)

*<br>输入参数:Object oPara 输出的对象

*<br>返回类型:无

*/

public void print(Object oPara){

    System、out、println(oPara);

}

/**

*<br>方法说明:打印输出(过载)

*<br>输入参数:Vector vPara 显示输出矢量对象

*<br>返回类型:无

*/

public void print(Vector<Object> vPara){

   for(int i=0;i<vPara、size();i++){

    System、out、println(vPara、elementAt(i));

   }

}

/**

*<br>方法说明:主方法,程序入口

*<br>输入参数:String[] args

*<br>返回类型:无

*/

public static void main(String[] args)

{

    operateVector ov = new operateVector();

    Vector<Object> vTemp = ov、buildVector();

    ov、print("vTemp0",vTemp);

    Vector<Object> vResult = ov、insert(vTemp,2,"添加的数据");

    ov、print("vResult",vResult);

    Vector<Object> vResultup = ov、updata(vResult,2,"修改的数据");

    ov、print("vResultmp",vResultup);

    Vector<Object> vResultnow = ov、delete(vResultup,2);

    ov、print("vResultnow",vResultnow);

}

}

package test5;

import java、util、*;

/**

* Title: 哈希表操作

* Description: 这是1个权限认证的例子,使用了哈希表作为数据的存储

* Filename: RoleRight、java

*/

public class RoleRight

{

private static Hashtable<String, String> rightList = new Hashtable<String, String>();

/**

*<br>方法说明:初始化数据

*<br>输入参数:

*<br>返回类型:

*/

public void init()

{

String[] accRoleList = {"admin","satrap","manager","user","guest"};

String[] rightCodeList = {"10001","10011","10021","20011","24011"};

for(int i=0;i<accRoleList、length;i++)

{

  rightList、put(accRoleList[i],rightCodeList[i]);

}

}

/**

*<br>方法说明:获取角色权限代码

*<br>输入参数:String accRole 角色名称

*<br>返回类型:String 权限代码

*/

public String getRight(String accRole)

{

if(rightList、containsKey(accRole))

  return (String)rightList、get(accRole);

else

  return null;

}

/**

*<br>方法说明:添加角色和代码信息

*<br>输入参数:String accRole 角色名称

*<br>输入参数:String rightCode 角色权限代码

*<br>返回类型:void (无)

*/

public void insert(String accRole,String rightCode)

{

rightList、put(accRole,rightCode);

}

/**

*<br>方法说明:删除角色权限

*<br>输入参数:String accRole 角色名称

*<br>返回类型:void(无)

*/

public void delete(String accRole)

{

if(rightList、containsKey(accRole))

 rightList、remove(accRole);

}

/**

*<br>方法说明:修改角色权限代码

*<br>输入参数:String accRole 角色名称

*<br>输入参数:String rightCode 角色权限代码

*<br>返回类型:void(无)

*/

public void update(String accRole,String rightCode)

{

//this、delete(accRole);

this、insert(accRole,rightCode);

}

/**

*<br>方法说明:打印哈希表中角色和代码对应表

*<br>输入参数:无

*<br>返回类型:无

*/

public void print()

{

Enumeration<String> RLKey = rightList、keys();

while(RLKey、hasMoreElements())

{

    String accRole = RLKey、nextElement()、toString();

    print(accRole+"="+this、getRight(accRole));

}

}

/**

*<br>方法说明:打印信息(过载)

*<br>输入参数:Object oPara 打印的信息内容

*<br>返回类型:无

*/

public void print(Object oPara)

{

System、out、println(oPara);

}

/**

*<br>方法说明:主方法,

*<br>输入参数:

*<br>返回类型:

*/

public static void main(String[] args)

{

RoleRight RR = new RoleRight();

RR、init();

RR、print();

RR、print("___________________________");

RR、insert("presider","10110");

RR、print();

RR、print("___________________________");

RR、update("presider","10100");

RR、print();

RR、print("___________________________");

RR、delete("presider");

RR、print();

}

}//end:)~

package test6;

/**

* Title: 树参数

* Description: 使用继承类,柳树就是树

* Filename: osier、java

*/

class tree

{

/**

*<br>方法说明:树的树根

*/

public void root()

{

String sSite = "土壤中";

String sFunction = "吸收养份";

print("位置:"+sSite);

print("功能:"+sFunction);

}

/**

*方法说明:树的树干

*/

public void bolo()

{

String sSite = "地面";

String sFunction = "传递养份";

print("位置:"+sSite);

print("功能:"+sFunction);

}

/**

*方法说明:树的树枝

*/

public void branch()

{

String sSite = "树干上";

String sFunction = "传递养份";

print("位置:"+sSite);

print("功能:"+sFunction);

}

/**

*方法说明:树的叶子

*/

public void leaf()

{

String sSite = "树梢";

String sFunction = "光合作用";

String sColor = "绿色";

print("位置:"+sSite);

print("功能:"+sFunction);

print("颜色:"+sColor);

}

/**

*方法说明:显示信息

*输入参数:Object oPara 显示的信息

*/

public void print(Object oPara)

{

System、out、println(oPara);

}

/**

*方法说明:主方法:

*/

public static void  main(String[] arges)

{

tree t = new tree();

t、print("描述1棵树:");

t、print("树根:");

t、root();

t、print("树干:");

t、bolo();

t、print("树枝:");

t、branch();

t、print("树叶:");

t、leaf();

}

}

/**

* Title: 柳树参数

* Description: 描述柳树的参数

*/

class osier extends tree

{

/**

*方法说明:过载树的树叶

*/

public void leaf()

{

super、leaf();

String sShape = "长形";

super、print("形状:"+sShape);

}

/**

*方法说明:扩展树的花

*/

public void flower()

{

print("哈哈,柳树没有花!!");

}

/**

*方法说明:主方法

*/

public static void  main(String[] args)

{

osier o = new osier();

o、print("柳树树根:");

o、root();

o、print("柳树树干:");

o、bolo();

o、print("柳树树枝:");

o、branch();

o、print("柳树树叶:");

o、leaf();

o、print("柳树花:");

o、flower();

}

}

package test7;

/**

*  Title:  接口和抽象函数

*  Description: 演示继承抽象函数和实现接口

*  Filename: newPlay、java

*/

//接口

interface player

{

int flag = 1;

void play();//播放

void pause();//暂停

void stop();//停止

}//end :)

//抽象类

abstract class playing

{

public void display(Object oPara)

{

System、out、println(oPara);

}

abstract void winRun();

}//end :)

//继承了playing抽象类和实现类player接口

public class newPlay extends playing implements player

{

public void play()

{

display("newPlay、play()");//这里只是演示,去掉了代码。

}

public void pause()

{

 display("newPlay、pause()");//这里只是演示,去掉了代码。

}

public void stop()

{

display("newPlay、stop()");//这里只是演示,去掉了代码。

}

void winRun()

{

display("newPlay、winRun()");//这里只是演示,去掉了代码。

}

public static void main(String[] args)

{

newPlay p = new newPlay();

p、play();

p、pause();

p、stop();

p、winRun();

}

}//end :)

package test8、com;

/**

* Title: 标识符

* Description: 演示标识符对类的访问控制

* Filename:

*/

public class classDemo1 {

// 公有方法

public void mechod1() {

    System、out、println("这是1个公有的方法!任何类都可以访问。");

}

// 授保护的方法

protected void mechod2() {

    System、out、println("这是1个受到保护的方法!只有子类可以访问。");

}

// 私有的方法

private void mechod3() {

    System、out、println("这是1个私有的方法!只有类本身才可以访问。");

}

public static void main(String[] args) {

    classDemo1 d = new classDemo1();

    d、mechod1();

    d、mechod2();

    d、mechod3();

}

}

package test8、com;

/**

* Title: 标识符

* Description: 演示标识符对类的访问控制

* Filename:

*/

public class classPlay

{

public static void main(String[] args){

classDemo1 d = new classDemo1();

d、mechod1();

d、mechod2();

//d、mechod3();

}

}

package test8、net;

import test8、com、classDemo1;

/**

* Title: 标识符

* Description: 演示标识符对类的访问控制

* Filename:

*/

public class classPlay

{

public static void main(String[] args){

classDemo1 d = new classDemo1();

d、mechod1();

//d、mechod2();

//d、mechod3();

}

}

package test9;

/**

* Title: 捕获异常和实现自己的异常

* Description: 通过继承Exception类来实现自己的异常类。并使用try-catch来捕获这个异常。

* Filename:

*/

class MyException extends Exception {

private static final long serialVersionUID = 1L;

public MyException() {

}

public MyException(String msg) {

    super(msg);

}

public MyException(String msg, int x) {

    super(msg);

    i = x;

}

public int val() {

    return i;

}

private int i;

}

public class DemoException {

/**

 *方法说明:使用MyException类中默认的构造器

 */

public static void a() throws MyException {

    System、out、println("Throwing MyException from a()");

    throw new MyException();

}

/**

 *方法说明:使用MyException类中带信息的构造器

 */

public static void b() throws MyException {

    System、out、println("Throwing MyException from b()");

    throw new MyException("Originated in b()");

}

/**

 *方法说明:使用了MyException中有编码的构造器

 */

public static void c() throws MyException {

    System、out、println("Throwing MyException from c()");

    throw new MyException("Originated in c()", 47);

}

public static void main(String[] args) {

    try {

    a();

    } catch (MyException e) {

    e、getMessage();

    }

    try {

    b();

    } catch (MyException e) {

    e、toString();

    }

    try {

    c();

    } catch (MyException e) {

    e、printStackTrace();

    System、out、println("error code: " + e、val());

    }

}

} // end :)

package test10;

import javax、swing、*;

import java、awt、*;

/**

* Title: 创建自己的窗体

* Description:

* Filename:mainFrame、java

*/

public class mainFrame extends JFrame {

private static final long serialVersionUID = 1L;

/**

 *方法说明:构造器,通过传递参数来完成窗体的绘制。

 *输入参数:String sTitle 窗体标题

 *输入参数:int iWidth 窗体的宽度

 *输入参数:int iHeight 窗体的高度 返回类型:

 */

public mainFrame(String sTitle, int iWidth, int iHeight) {

    Dimension dim = Toolkit、getDefaultToolkit()、getScreenSize();// 获取屏幕尺寸

    ImageIcon ii = new ImageIcon("middle、gif");

    setTitle(sTitle);// 设置窗体标题

    setIconImage(ii、getImage());// 设置窗体的图标

    setDefaultCloseOperation(JFrame、DISPOSE_ON_CLOSE);// 设置但关闭窗体时退出程序

    setSize(iWidth, iHeight);// 设置窗体大小

    int w = getSize()、width;// 获取窗体宽度

    int h = getSize()、height;// 获取窗体高度

    System、out、println("窗体宽:" + w + " 窗体高:" + h);

    int x = (dim、width - w) / 2;

    int y = (dim、height - h) / 2;

    setLocation(x, y);// 将窗体移到屏幕中间

    setVisible(true);// 显示窗体

}

public static void main(String[] args) {

    JFrame、setDefaultLookAndFeelDecorated(true);// 使用最新的SWING外观

    new mainFrame("main Frame Demo", 400, 300);

}

}

4 程序员面试题精选(36道,中等难度)

(01)将二元查找树转变成排序的双向链表

  题目:输入1棵二元查找树,将该二元查找树转换成1个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。

  比如将二元查找树

10

/    \

6       14

/  \     /  \

4     8  12   16

转换成双向链表

4=6=8=10=12=14=16。

  分析:本题是微软的面试题。很多与树相关的题目都是用递归的思路来解决,本题也不例外。下面我们用两种不同的递归思路来分析。

  思路1:当我们到达某1结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成1个排好序的左子链表,再调整其右子树转换右子链表。最近链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。

  思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问1个结点,假设之前访问过的结点已经调整成1个排序双向链表,我们再将调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成1个排序双向链表了。

参考代码:

首先我们定义二元查找树结点的数据结构如下:

struct BSTreeNode // a node in the binary search tree

{

int          m_nValue; // value of node

BSTreeNode  *m_pLeft;  // left child of node

BSTreeNode  *m_pRight; // right child of node

};

思路1对应的代码:

///

// Covert a sub binary-search-tree into a sorted double-linked list

// Input: pNode - the head of the sub tree

//        asRight - whether pNode is the right child of its parent

// Output: if asRight is true, return the least node in the sub-tree

//         else return the greatest node in the sub-tree

///

BSTreeNode* ConvertNode(BSTreeNode* pNode, bool asRight)

{

if(!pNode)

return NULL;

BSTreeNode *pLeft = NULL;

BSTreeNode *pRight = NULL;

// Convert the left sub-tree

if(pNode->m_pLeft)

pLeft = ConvertNode(pNode->m_pLeft, false);

// Connect the greatest node in the left sub-tree to the current node

if(pLeft)

{

pLeft->m_pRight = pNode;

pNode->m_pLeft = pLeft;

}

// Convert the right sub-tree

if(pNode->m_pRight)

pRight = ConvertNode(pNode->m_pRight, true);

// Connect the least node in the right sub-tree to the current node

if(pRight)

{

pNode->m_pRight = pRight;

pRight->m_pLeft = pNode;

}

BSTreeNode *pTemp = pNode;

// If the current node is the right child of its parent,

// return the least node in the tree whose root is the current node

if(asRight)

{

while(pTemp->m_pLeft)

pTemp = pTemp->m_pLeft;

}

// If the current node is the left child of its parent,

// return the greatest node in the tree whose root is the current node

else

{

while(pTemp->m_pRight)

pTemp = pTemp->m_pRight;

}

return pTemp;

}

///

// Covert a binary search tree into a sorted double-linked list

// Input: the head of tree

// Output: the head of sorted double-linked list

///

BSTreeNode* Convert(BSTreeNode* pHeadOfTree)

{

// As we want to return the head of the sorted double-linked list,

// we set the second parameter to be true

return ConvertNode(pHeadOfTree, true);

}

思路二对应的代码:

///

// Covert a sub binary-search-tree into a sorted double-linked list

// Input: pNode -           the head of the sub tree

//        pLastNodeInList - the tail of the double-linked list

///

void ConvertNode(BSTreeNode* pNode, BSTreeNode*& pLastNodeInList)

{

if(pNode == NULL)

return;

BSTreeNode *pCurrent = pNode;

// Convert the left sub-tree

if (pCurrent->m_pLeft != NULL)

ConvertNode(pCurrent->m_pLeft, pLastNodeInList);

// Put the current node into the double-linked list

pCurrent->m_pLeft = pLastNodeInList;

if(pLastNodeInList != NULL)

pLastNodeInList->m_pRight = pCurrent;

pLastNodeInList = pCurrent;

// Convert the right sub-tree

if (pCurrent->m_pRight != NULL)

ConvertNode(pCurrent->m_pRight, pLastNodeInList);

}

///

// Covert a binary search tree into a sorted double-linked list

// Input: pHeadOfTree - the head of tree

// Output: the head of sorted double-linked list

///

BSTreeNode* Convert_Solution1(BSTreeNode* pHeadOfTree)

{

BSTreeNode *pLastNodeInList = NULL;

ConvertNode(pHeadOfTree, pLastNodeInList);

// Get the head of the double-linked list

BSTreeNode *pHeadOfList = pLastNodeInList;

while(pHeadOfList && pHeadOfList->m_pLeft)

pHeadOfList = pHeadOfList->m_pLeft;

return pHeadOfList;

}

(02)设计包含min函数的栈

题目:定义栈的数据结构,要求添加1个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。

分析:这是去年google的1道面试题。

我看到这道题目时,第1反应就是每次push1个新元素时,将栈里所有逆序元素排序。这样栈顶元素将是最小元素。但由于不能保证最后push进栈的元素最先出栈,这种思路设计的数据结构已经不是1个栈了。

在栈里添加1个成员变量存放最小元素(或最小元素的位置)。每次push1个新元素进栈的时候,如果该元素比当前的最小元素还要小,则更新最小元素。

乍1看这样思路挺好的。但仔细1想,该思路存在1个重要的问题:如果当前最小元素被pop出去,如何才能得到下1个最小元素?

因此仅仅只添加1个成员变量存放最小元素(或最小元素的位置)是不够的。我们需要1个辅助栈。每次push1个新元素的时候,同时将最小元素(或最小元素的位置。考虑到栈元素的类型可能是复杂的数据结构,用最小元素的位置将能减少空间消耗)push到辅助栈中;每次pop1个元素出栈的时候,同时pop辅助栈。

参考代码:

#include <deque>

#include <assert、h>

template <typename T> class CStackWithMin

{

public:

CStackWithMin(void) {}

virtual ~CStackWithMin(void) {}

T& top(void);

const T& top(void) const;

void push(const T& value);

void pop(void);

const T& min(void) const;

private:

T>m_data;// theelements of stack

size_t>m_minIndex;// the indicesof minimum elements

};

// get the last element of mutable stack

template <typename T> T& CStackWithMin<T>::top()

{

return m_data、back();

}

// get the last element of non-mutable stack

template <typename T> const T& CStackWithMin<T>::top() const

{

return m_data、back();

}

// insert an elment at the end of stack

template <typename T> void CStackWithMin<T>::push(const T& value)

{

// append the data into the end of m_data

m_data、push_back(value);

// set the index of minimum elment in m_data at the end of m_minIndex

if(m_minIndex、size() == 0)

m_minIndex、push_back(0);

else

{

if(value < m_data[m_minIndex、back()])

m_minIndex、push_back(m_data、size() - 1);

else

m_minIndex、push_back(m_minIndex、back());

}

}

// erease the element at the end of stack

template <typename T> void CStackWithMin<T>::pop()

{

// pop m_data

m_data、pop_back();

// pop m_minIndex

m_minIndex、pop_back();

}

// get the minimum element of stack

template <typename T> const T& CStackWithMin<T>::min() const

{

assert(m_data、size() > 0);

assert(m_minIndex、size() > 0);

return m_data[m_minIndex、back()];

}

举个例子演示上述代码的运行过程:

步骤              数据栈            辅助栈                最小值

1、push 3    3          0             3

2、push 4    3,4        0,0           3

3、push 2    3,4,2      0,0,2         2

4、push 1    3,4,2,1    0,0,2,3       1

5、pop       3,4,2      0,0,2         2

6、pop       3,4        0,0           3

7、push 0    3,4,0      0,0,2         0

讨论:如果思路正确,编写上述代码不是1件很难的事情。但如果能注意1些细节无疑能在面试中加分。比如我在上面的代码中做了如下的工作:

·         用模板类实现。如果别人的元素类型只是int类型,模板将能给面试官带来好印象;

·         两个版本的top函数。在很多类中,都需要提供const和非const版本的成员访问函数;

·         min函数中assert。将代码写的尽量安全是每个软件公司对程序员的要求;

·         添加1些注释。注释既能提高代码的可读性,又能增加代码量,何乐而不为?

总之,在面试时如果时间允许,尽量将代码写的漂亮1些。说不定代码中的几个小亮点就能让自己轻松拿到心仪的Offer。

(03) 求子数组的最大和

[折叠]

题目:输入1个整形数组,数组里有正数也有负数。数组中连续的1个或多个整数组成1个子数组,每个子数组都有1个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。

示例输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18。

分析:本题最初为2005年浙江大学计算机系的考研题的最后1道程序设计题,在2006年里包括google在内的很多知名公司都将本题当作面试题。由于本题在网络中广为流传,本题也顺利成为2006年程序员面试题中经典中的经典。

如果不考虑时间复杂度,我们可以枚举出所有子数组并求出他们的和。不过非常遗憾的是,由于长度为n的数组有O(n2)个子数组;而且求1个长度为n的数组的和的时间复杂度为O(n)。因此这种思路的时间是O(n3)。

很容易理解,当我们加上1个正数时,和会增加;当我们加上1个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。基于这样的思路,我们可以写出如下代码。

参考代码:

/

// Find the greatest sum of all sub-arrays

// Return value: if the input is valid, return true, otherwise return false

/

bool FindGreatestSumOfSubArray

(

int *pData,           // an array

unsigned int nLength, // the length of array

int &nGreatestSum     // the greatest sum of all sub-arrays

)

{

// if the input is invalid, return false

if((pData == NULL) || (nLength == 0))

return false;

int nCurSum = nGreatestSum = 0;

for(unsigned int i = 0; i < nLength; ++i)

{

nCurSum += pData[i];

// if the current sum is negative, discard it

if(nCurSum < 0)

nCurSum = 0;

// if a greater sum is found, update the greatest sum

if(nCurSum > nGreatestSum)

nGreatestSum = nCurSum;

}

// if all data are negative, find the greatest element in the array

if(nGreatestSum == 0)

{

nGreatestSum = pData[0];

for(unsigned int i = 1; i < nLength; ++i)

{

if(pData[i] > nGreatestSum)

nGreatestSum = pData[i];

}

}

return true;

}

讨论:上述代码中有两点值得和大家讨论1下:

·         函数的返回值不是子数组和的最大值,而是1个判断输入是否有效的标志。如果函数返回值的是子数组和的最大值,那么当输入1个空指针是应该返回什么呢?返回0?那这个函数的用户怎么区分输入无效和子数组和的最大值刚好是0这两中情况呢?基于这个考虑,本人认为将子数组和的最大值以引用的方式放到参数列表中,同时让函数返回1个函数是否正常执行的标志。

·         输入有1类特殊情况需要特殊处理。当输入数组中所有整数都是负数时,子数组和的最大值就是数组中的最大元素。

(04) 在二元树中找出和为某1值的所有路径   [折叠]

题目:输入1个整数和1棵二元树。从树的根结点开始往下访问1直到叶结点所经过的所有结点形成1条路径。打印出和与输入整数相等的所有路径。

示例输入整数22和如下二元树

10

/   \

5     12

/   \

 4     7

则打印出两条路径:10, 12和10, 5, 7。

二元树结点的数据结构定义为:

struct BinaryTreeNode // a node in the binary tree

{

int              m_nValue; // value of node

BinaryTreeNode  *m_pLeft;  // left child of node

BinaryTreeNode  *m_pRight; // right child of node

};

分析:这是百度的1道笔试题,考查对树这种基本数据结构以及递归函数的理解。

当访问到某1结点时,将该结点添加到路径上,并累加当前结点的值。如果当前结点为叶结点并且当前路径的和刚好等于输入的整数,则当前的路径符合要求,我们将它打印出来。如果当前结点不是叶结点,则继续访问它的子结点。当前结点访问结束后,递归函数将自动回到父结点。因此我们在函数退出之前要在路径上删除当前结点并减去当前结点的值,以确保返回父结点时路径刚好是根结点到父结点的路径。我们不难看出保存路径的数据结构实际上是1个栈结构,因为路径要与递归调用状态1致,而递归调用本质就是1个压栈和出栈的过程。

参考代码:

///

// Find paths whose sum equal to expected sum

///

void FindPath

(

BinaryTreeNode*   pTreeNode,    // a node of binary tree

int               expectedSum,  // the expected sum

std::vector<int>&path,        // a pathfrom root to current node

int&              currentSum    // the sum of path

)

{

if(!pTreeNode)

return;

currentSum += pTreeNode->m_nValue;

path、push_back(pTreeNode->m_nValue);

// if the node is a leaf, and the sum is same as pre-defined,

// the path is what we want、 print the path

bool isLeaf = (!pTreeNode->m_pLeft && !pTreeNode->m_pRight);

if(currentSum == expectedSum && isLeaf)

{

std::vector<int>::iterator iter =path、begin();

for(; iter != path、end(); ++ iter)

std::cout<<*iter<<'\t';

std::cout<<std::endl;

}

// if the node is not a leaf, goto its children

if(pTreeNode->m_pLeft)

FindPath(pTreeNode->m_pLeft, expectedSum, path, currentSum);

if(pTreeNode->m_pRight)

FindPath(pTreeNode->m_pRight, expectedSum, path, currentSum);

// when we finish visiting a node and return to its parent node,

// we should delete this node from the path and

// minus the node's value from the current sum

currentSum -= pTreeNode->m_nValue; //!!I think here is no use

path、pop_back();

}

(05)查找最小的k个元素 [折叠]

题目:输入n个整数,输出其中最小的k个。

示例输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。

分析:这道题最简单的思路莫过于将输入的n个整数排序,这样排在最前面的k个数就是最小的k个数。只是这种思路的时间复杂度为O(nlogn)。我们试着寻找更快的解决思路。

我们可以开辟1个长度为k的数组。每次从输入的n个整数中读入1个数。如果数组中已经插入的元素少于k个,则将读入的整数直接放到数组中。否则长度为k的数组已经满了,不能再往数组里插入元素,只能替换了。如果读入的这个整数比数组中已有k个整数的最大值要小,则用读入的这个整数替换这个最大值;如果读入的整数比数组中已有k个整数的最大值还要大,则读入的这个整数不可能是最小的k个整数之1,抛弃这个整数。这种思路相当于只要排序k个整数,因此时间复杂可以降到O(n+nlogk)。通常情况下k要远小于n,所以这种办法要优于前面的思路。

这是我能够想出来的最快的解决方案。不过从给面试官留下更好印象的角度出发,我们可以进1步将代码写得更漂亮1些。从上面的分析,当长度为k的数组已经满了之后,如果需要替换,每次替换的都是数组中的最大值。在常用的数据结构中,能够在O(1)时间里得到最大值的数据结构为最大堆。因此我们可以用堆(heap)来代替数组。

另外,自己重头开始写1个最大堆需要1定量的代码。我们现在不需要重新去发明车轮,因为前人早就发明出来了。同样,STL中的set和multiset为我们做了很好的堆的实现,我们可以拿过来用。既偷了懒,又给面试官留下熟悉STL的好印象,何乐而不为之?

参考代码:

#include <set>

#include <vector>

#include <iostream>

using namespace std;

typedef multiset<int, greater<int> >  IntHeap;

///

// find k least numbers in a vector

///

void FindKLeastNumbers

(

const vector<int>& data,               // a vector of data

IntHeap& leastNumbers,                 // k least numbers, output

unsigned int k

)

{

leastNumbers、clear();

if(k == 0 || data、size() < k)

return;

vector<int>::const_iterator iter = data、begin();

for(; iter != data、end(); ++ iter)

{

// if less than k numbers was inserted into leastNumbers

if((leastNumbers、size()) < k)

leastNumbers、insert(*iter);

// leastNumbers contains k numbers and it's full now

else

{

// first number in leastNumbers is the greatest one

IntHeap::iterator iterFirst = leastNumbers、begin();

// if is less than the previous greatest number

if(*iter < *(leastNumbers、begin()))

{

// replace the previous greatest number

leastNumbers、erase(iterFirst);

leastNumbers、insert(*iter);

}

}

}

}

(06)判断整数序列是不是二元查找树的后序遍历结果

[折叠]

题目:输入1个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。

示例输入5、7、6、9、11、10、8,由于这1整数序列是如下树的后序遍历结果:

8

/  \

6    10

/ \    / \

5   7   9  11

因此返回true。

如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。

分析:这是1道trilogy的笔试题,主要考查对二元查找树的理解。

在后续遍历得到的序列中,最后1个元素为树的根结点。从头开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第1个大于跟结点开始到跟结点前面的1个元素为止,所有元素都应该大于跟结点,因为这部分元素对应的是树的右子树。根据这样的划分,将序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。

参考代码:

using namespace std;

///

// Verify whether a squence of integers are the post order traversal

// of a binary search tree (BST)

// Input: squence - the squence of integers

//        length  - the length of squence

// Return: return ture if the squence is traversal result of a BST,

//         otherwise, return false

///

bool verifySquenceOfBST(int squence[], int length)

{

if(squence == NULL || length <= 0)

return false;

// root of a BST is at the end of post order traversal squence

int root = squence[length - 1];

// the nodes in left sub-tree are less than the root

int i = 0;

for(; i < length - 1; ++ i)

{

if(squence[i] > root)

break;

}

// the nodes in the right sub-tree are greater than the root

int j = i;

for(; j < length - 1; ++ j)

{

if(squence[j] < root)

return false;

}

// verify whether the left sub-tree is a BST

bool left = true;

if(i > 0)

left = verifySquenceOfBST(squence, i);

// verify whether the right sub-tree is a BST

bool right = true;

if(i < length - 1)

right = verifySquenceOfBST(squence + i, length - i - 1);

return (left && right);

}

(07) 翻转句子中单词的顺序   [折叠]

题目:输入1个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母1样处理。

示例输入“I am a student、”,则输出“student、 a am I”。

分析:由于编写string相关代码能够反映程序员的编程能力和编程习惯,与string相关的问题1直是程序员笔试、面试题的热门题目。本题也曾多次受到包括微软在内的大量公司的青睐。

由于本题需要翻转句子,我们先颠倒句子中的所有字符。这时,不但翻转了句子中单词的顺序,而且单词内字符也被翻转了。我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持1致。

还是以上面的输入为例子。翻转“I am a student、”中所有字符得到“、tneduts a ma I”,再翻转每个单词中字符的顺序得到“students、 a am I”,正是符合要求的输出。

参考代码:

///

// Reverse a string between two pointers

// Input: pBegin - the begin pointer in a string

//        pEnd   - the end pointer in a string

///

void Reverse(char *pBegin, char *pEnd)

{

if(pBegin == NULL || pEnd == NULL)

return;

while(pBegin < pEnd)

{

char temp = *pBegin;

*pBegin = *pEnd;

*pEnd = temp;

pBegin ++, pEnd --;

}

}

///

// Reverse the word order in a sentence, but maintain the character

// order inside a word

// Input: pData - the sentence to be reversed

///

char* ReverseSentence(char *pData)

{

if(pData == NULL)

return NULL;

char *pBegin = pData;

char *pEnd = pData;

while(*pEnd != '\0')

pEnd ++;

pEnd--;

// Reverse the whole sentence

Reverse(pBegin, pEnd);

// Reverse every word in the sentence

pBegin = pEnd = pData;

while(*pBegin != '\0')

{

if(*pBegin == ' ')

{

pBegin ++;

pEnd ++;

continue;

}

// A word is between with pBegin and pEnd, reverse it

else if(*pEnd == ' ' || *pEnd == '\0')

{

Reverse(pBegin, --pEnd);

pBegin = ++pEnd;

}

else

{

pEnd ++;

}

}

return pData;

}

(08) 求1+2+、、、+n

题目:求1+2+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。

分析:这道题没有多少实际意义,因为在软件开发中不会有这么变态的限制。但这道题却能有效地考查发散思维能力,而发散思维能力能反映出对编程相关技术理解的深刻程度。

通常求1+2+…+n除了用公式n(n+1)/2之外,无外乎循环和递归两种思路。由于已经明确限制for和while的使用,循环已经不能再用了。同样,递归函数也需要用if语句或者条件判断语句来判断是继续递归下去还是终止递归,但现在题目已经不允许使用这两种语句了。

我们仍然围绕循环做文章。循环只是让相同的代码执行n遍而已,我们完全可以不用for和while达到这个效果。比如定义1个类,我们new1含有n个这种类型元素的数组,那么该类的构造函数将确定会被调用n次。我们可以将需要执行的代码放到构造函数里。如下代码正是基于这个思路:

class Temp

{

public:

Temp() { ++ N; Sum += N; }

static void Reset() { N = 0; Sum = 0; }

static int GetSum() { return Sum; }

private:

static int N;

static int Sum;

};

int Temp::N = 0;

int Temp::Sum = 0;

int solution1_Sum(int n)

{

Temp::Reset();

Temp *a = new Temp[n];

delete []a;

a = 0;

return Temp::GetSum();

}

我们同样也可以围绕递归做文章。既然不能判断是不是应该终止递归,我们不妨定义两个函数。1个函数充当递归函数的角色,另1个函数处理终止递归的情况,我们需要做的就是在两个函数里二选1。从二选1我们很自然的想到布尔变量,比如ture(1)的时候调用第1个函数,false(0)的时候调用第2个函数。那现在的问题是如和将数值变量n转换成布尔值。如果对n连续做两次反运算,即!!n,那么非零的n转换为true,0转换为false。有了上述分析,我们再来看下面的代码:

class A;

A* Array[2];

class A

{

public:

virtual int Sum (int n) { return 0; }

};

class B: public A

{

public:

virtual int Sum (int n) { return Array[!!n]->Sum(n-1)+n; }

};

int solution2_Sum(int n)

{

A a;

B b;

Array[0] = &a;

Array[1] = &b;

int value = Array[1]->Sum(n);

return value;

}

这种方法是用虚函数来实现函数的选择。当n不为零时,执行函数B::Sum;当n为0时,执行A::Sum。我们也可以直接用函数指针数组,这样可能还更直接1些:

typedef int (*fun)(int);

int solution3_f1(int i)

{

return 0;

}

int solution3_f2(int i)

{

fun f[2]={solution3_f1, solution3_f2};

return i+f[!!i](i-1);

}

另外我们还可以让编译器帮我们来完成类似于递归的运算,比如如下代码:

template <int n> struct solution4_Sum

{

enum Value { N = solution4_Sum<n - 1>::N + n};

};

template <> struct solution4_Sum<1>

{

enum Value { N = 1};

};

solution4_Sum<100>::N就是1+2+、、、+100的结果。当编译器看到solution4_Sum<100>时,就是为模板类solution4_Sum以参数100生成该类型的代码。但以100为参数的类型需要得到以99为参数的类型,因为solution4_Sum<100>::N=solution4_Sum<99>::N+100。这个过程会递归1直到参数为1的类型,由于该类型已经显式定义,编译器无需生成,递归编译到此结束。由于这个过程是在编译过程中完成的,因此要求输入n必须是在编译期间就能确定,不能动态输入。这是该方法最大的缺点。而且编译器对递归编译代码的递归深度是有限制的,也就是要求n不能太大。

大家还有更多、更巧妙的思路吗?欢迎讨论^_^

(09) 查找链表中倒数第k个结点

题目:输入1个单向链表,输出该链表中倒数第k个结点。链表的倒数第0个结点为链表的尾指针。链表结点定义如下:

struct ListNode

{

int       m_nKey;

ListNode* m_pNext;

};

分析:为了得到倒数第k个结点,很自然的想法是先走到链表的尾端,再从尾端回溯k步。可是输入的是单向链表,只有从前往后的指针而没有从后往前的指针。因此我们需要打开我们的思路。

既然不能从尾结点开始遍历这个链表,我们还是将思路回到头结点上来。假设整个链表有n个结点,那么倒数第k个结点是从头结点开始的第n-k-1个结点(从0开始计数)。如果我们能够得到链表中结点的个数n,那我们只要从头结点开始往后走n-k-1步就可以了。如何得到结点数n?这个不难,只需要从头开始遍历链表,每经过1个结点,计数器加1就行了。

这种思路的时间复杂度是O(n),但需要遍历链表两次。第1次得到链表中结点个数n,第2次得到从头结点开始的第n-k-1个结点即倒数第k个结点。

如果链表的结点数不多,这是1种很好的方法。但如果输入的链表的结点个数很多,有可能不能1次性将整个链表都从硬盘读入物理内存,那么遍历两遍意味着1个结点需要两次从硬盘读入到物理内存。我们知道将数据从硬盘读入到内存是非常耗时间的操作。我们能不能将链表遍历的次数减少到1?如果可以,将能有效地提高代码执行的时间效率。

如果我们在遍历时维持两个指针,第1个指针从链表的头指针开始遍历,在第k-1步之前,第2个指针保持不动;在第k-1步开始,第2个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第1个(走在前面的)指针到达链表的尾结点时,第2个指针(走在后面的)指针正好是倒数第k个结点。

这种思路只需要遍历链表1次。对于很长的链表,只需要将每个结点从硬盘导入到内存1次。因此这1方法的时间效率前面的方法要高。

思路1的参考代码:

///

// Find the kth node from the tail of a list

// Input: pListHead - the head of list

//        k         - the distance to the tail

// Output: the kth node from the tail of a list

///

ListNode* FindKthToTail_Solution1(ListNode* pListHead, unsigned int k)

{

if(pListHead == NULL)

return NULL;

// count the nodes number in the list

ListNode *pCur = pListHead;

unsigned int nNum = 0;

while(pCur->m_pNext != NULL)

{

pCur = pCur->m_pNext;

nNum ++;

}

// if the number of nodes in the list is less than k

// do nothing

if(nNum < k)

return NULL;

// the kth node from the tail of a list

// is the (n - k)th node from the head

pCur = pListHead;

for(unsigned int i = 0; i < nNum - k; ++ i)

pCur = pCur->m_pNext;

return pCur;

}

思路二的参考代码:

///

// Find the kth node from the tail of a list

// Input: pListHead - the head of list

//        k         - the distance to the tail

// Output: the kth node from the tail of a list

///

ListNode* FindKthToTail_Solution2(ListNode* pListHead, unsigned int k)

{

if(pListHead == NULL)

return NULL;

ListNode *pAhead = pListHead;

ListNode *pBehind = NULL;

for(unsigned int i = 0; i < k; ++ i)

{

if(pAhead->m_pNext != NULL)

pAhead = pAhead->m_pNext;

else

{

// if the number of nodes in the list is less than k,

// do nothing

return NULL;

}

}

pBehind = pListHead;

// the distance between pAhead and pBehind is k

// when pAhead arrives at the tail, p

// Behind is at the kth node from the tail

while(pAhead->m_pNext != NULL)

{

pAhead = pAhead->m_pNext;

pBehind = pBehind->m_pNext;

}

return pBehind;

}

讨论:这道题的代码有大量的指针操作。在软件开发中,错误的指针操作是大部分问题的根源。因此每个公司都希望程序员在操作指针时有良好的习惯,比如使用指针之前判断是不是空指针。这些都是编程的细节,但如果这些细节将握得不好,很有可能就会和心仪的公司失之交臂。

另外,这两种思路对应的代码都含有循环。含有循环的代码经常出的问题是在循环结束条件的判断。是该用小于还是小于等于?是该用k还是该用k-1?由于题目要求的是从0开始计数,而我们的习惯思维是从1开始计数,因此首先要想好这些边界条件再开始编写代码,再者要在编写完代码之后再用边界值、边界值减1、边界值加1都运行1次(在纸上写代码就只能在心里运行了)。

扩展:和这道题类似的题目还有:输入1个单向链表。如果该链表的结点数为奇数,输出中间的结点;如果链表结点数为偶数,输出中间两个结点前面的1个。如果各位感兴趣,请自己分析并编写代码。

(10) 在排序数组中查找和为给定值的两个数字

题目:输入1个已经按升序排序过的数组和1个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意1对即可。

示例输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。

分析:如果我们不考虑时间复杂度,最简单想法的莫过去先在数组中固定1个数字,再依次判断数组中剩下的n-1个数字与它的和是不是等于输入的数字。可惜这种思路需要的时间复杂度是O(n2)。

我们假设现在随便在数组中找到两个数。如果它们的和等于输入的数字,那太好了,我们找到了要找的两个数字;如果小于输入的数字呢?我们希望两个数字的和再大1点。由于数组已经排好序了,我们是不是可以将较小的数字的往后面移动1个数字?因为排在后面的数字要大1些,那么两个数字的和也要大1些,就有可能等于输入的数字了;同样,当两个数字的和大于输入的数字的时候,我们将较大的数字往前移动,因为排在数组前面的数字要小1些,它们的和就有可能等于输入的数字了。

我们将前面的思路整理1下:最初我们找到数组的第1个数字和最后1个数字。当两个数字的和大于输入的数字时,将较大的数字往前移动;当两个数字的和小于数字时,将较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是从数组的两端向数组的中间扫描。

问题是这样的思路是不是正确的呢?这需要严格的数学证明。感兴趣的读者可以自行证明1下。

参考代码:

///

// Find two numbers with a sum in a sorted array

// Output: ture is found such two numbers, otherwise false

///

bool FindTwoNumbersWithSum

(

int data[],           // a sorted array

unsigned int length,  // the length of the sorted array

int sum,              // the sum

int& num1,            // the first number, output

int& num2             // the second number, output

)

{

bool found = false;

if(length < 1)

return found;

int ahead = length - 1;

int behind = 0;

while(ahead > behind)

{

long long curSum = data[ahead] + data[behind];

// if the sum of two numbers is equal to the input

// we have found them

if(curSum == sum)

{

num1 = data[behind];

num2 = data[ahead];

found = true;

break;

}

// if the sum of two numbers is greater than the input

// decrease the greater number

else if(curSum > sum)

ahead --;

// if the sum of two numbers is less than the input

// increase the less number

else

behind ++;

}

return found;

}

扩展:如果输入的数组是没有排序的,但知道里面数字的范围,其他条件不变,如和在O(n)时间里找到这两个数字?

(11) 求二元查找树的镜像

题目:输入1颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。用递归和循环两种方法完成树的镜像转换。

示例输入:

8

/  \

6      10

/\       /\

5  7    9   11

输出:

8

/  \

10    6

/\      /\

11  9  7  5

定义二元查找树的结点为:

struct BSTreeNode // a node in the binary search tree (BST)

{

int          m_nValue; // value of node

BSTreeNode  *m_pLeft;  // left child of node

BSTreeNode  *m_pRight; // right child of node

};

分析:尽管我们可能1下子不能理解镜像是什么意思,但上面的例子给我们的直观感觉,就是交换结点的左右子树。我们试着在遍历例子中的二元查找树的同时来交换每个结点的左右子树。遍历时首先访问头结点8,我们交换它的左右子树得到:

8

/  \

10    6

/\      /\

9  11  5  7

我们发现两个结点6和10的左右子树仍然是左结点的值小于右结点的值,我们再试着交换他们的左右子树,得到:

8

/  \

10    6

/\      /\

11  9  7   5

刚好就是要求的输出。

上面的分析印证了我们的直觉:在遍历二元查找树时每访问到1个结点,交换它的左右子树。这种思路用递归不难实现,将遍历二元查找树的代码稍作修改就可以了。参考代码如下:

///

// Mirror a BST (swap the left right child of each node) recursively

// the head of BST in initial call

///

void MirrorRecursively(BSTreeNode *pNode)

{

if(!pNode)

return;

// swap the right and left child sub-tree

BSTreeNode *pTemp = pNode->m_pLeft;

pNode->m_pLeft = pNode->m_pRight;

pNode->m_pRight = pTemp;

// mirror left child sub-tree if not null

if(pNode->m_pLeft)

MirrorRecursively(pNode->m_pLeft);

// mirror right child sub-tree if not null

if(pNode->m_pRight)

MirrorRecursively(pNode->m_pRight);

}

由于递归的本质是编译器生成了1个函数调用的栈,因此用循环来完成同样任务时最简单的办法就是用1个辅助栈来模拟递归。首先我们将树的头结点放入栈中。在循环中,只要栈不为空,弹出栈的栈顶结点,交换它的左右子树。如果它有左子树,将它的左子树压入栈中;如果它有右子树,将它的右子树压入栈中。这样在下次循环中就能交换它儿子结点的左右子树了。参考代码如下:

///

// Mirror a BST (swap the left right child of each node) Iteratively

// Input: pTreeHead: the head of BST

///

void MirrorIteratively(BSTreeNode *pTreeHead)

{

if(!pTreeHead)

return;

std::stack<BSTreeNode*>stackTreeNode;

stackTreeNode、push(pTreeHead);

while(stackTreeNode、size())

{

BSTreeNode *pNode = stackTreeNode、top();

stackTreeNode、pop();

// swap the right and left child sub-tree

BSTreeNode *pTemp = pNode->m_pLeft;

pNode->m_pLeft = pNode->m_pRight;

pNode->m_pRight = pTemp;

// push left child sub-tree into stack if not null

if(pNode->m_pLeft)

stackTreeNode、push(pNode->m_pLeft);

// push right child sub-tree into stack if not null

if(pNode->m_pRight)

stackTreeNode、push(pNode->m_pRight);

}

}

(12) 从上往下遍历二元树

题目:输入1颗二元树,从上往下按层打印树的每个结点,同1层中按照从左往右的顺序打印。

示例输入

8

/  \

6    10

/\     /\

5  7   9  11

输出8   6   10   5   7   9   11。

分析:这曾是微软的1道面试题。这道题实质上是要求遍历1棵二元树,只不过不是我们熟悉的前序、中序或者后序遍历。

我们从树的根结点开始分析。自然先应该打印根结点8,同时为了下次能够打印8的两个子结点,我们应该在遍历到8时将子结点6和10保存到1个数据容器中。现在数据容器中就有两个元素6 和10了。按照从左往右的要求,我们先取出6访问。打印6的同时要将6的两个子结点5和7放入数据容器中,此时数据容器中有三个元素10、5和7。接下来我们应该从数据容器中取出结点10访问了。注意10比5和7先放入容器,此时又比5和7先取出,就是我们通常说的先入先出。因此不难看出这个数据容器的类型应该是个队列。

既然已经确定数据容器是1个队列,现在的问题变成怎么实现队列了。实际上我们无需自己动手实现1个,因为STL已经为我们实现了1个很好的deque(两端都可以进出的队列),我们只需要拿过来用就可以了。

我们知道树是图的1种特殊退化形式。同时如果对图的深度优先遍历和广度优先遍历有比较深刻的理解,将不难看出这种遍历方式实际上是1种广度优先遍历。因此这道题的本质是在二元树上实现广度优先遍历。

参考代码:

#include <deque>

#include <iostream>

using namespace std;

struct BTreeNode // a node in the binary tree

{

int         m_nValue; // value of node

BTreeNode  *m_pLeft;  // left child of node

BTreeNode  *m_pRight; // right child of node

};

///

// Print a binary tree from top level to bottom level

// Input: pTreeRoot - the root of binary tree

///

void PrintFromTopToBottom(BTreeNode *pTreeRoot)

{

if(!pTreeRoot)

return;

// get a empty queue

deque<BTreeNode *> dequeTreeNode;

// insert the root at the tail of queue

dequeTreeNode、push_back(pTreeRoot);

while(dequeTreeNode、size())

{

// get a node from the head of queue

BTreeNode *pNode = dequeTreeNode、front();

dequeTreeNode、pop_front();

// print the node

cout << pNode->m_nValue << ' ';

// print its left child sub-tree if it has

if(pNode->m_pLeft)

dequeTreeNode、push_back(pNode->m_pLeft);

// print its right child sub-tree if it has

if(pNode->m_pRight)

dequeTreeNode、push_back(pNode->m_pRight);

}

}

(13) 第1个只出现1次的字符

题目:在1个string中找到第1个只出现1次的字符。如输入abaccdeff,则输出b。

分析:这道题是2006年google的1道笔试题。

看到这道题时,最直观的想法是从头开始扫描这个string中的每个字符。当访问到某字符时拿这个字符和后面的每个字符相比较,如果在后面没有发现重复的字符,则该字符就是只出现1次的字符。如果string有n个字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路时间复杂度是O(n2)。我们试着去找1个更快的方法。

由于题目与字符出现的次数相关,我们是不是可以统计每个字符在该string中出现的次数?要达到这个目的,我们需要1个数据容器来存放每个字符的出现次数。在这个数据容器中可以根据字符来查找它出现的次数,也就是说这个容器的作用是将1个字符映射成1个数字。在常用的数据容器中,哈希表正是这个用途。

哈希表是1种比较复杂的数据结构。由于比较复杂,STL中没有实现哈希表,因此需要我们自己实现1个。但由于本题的特殊性,我们只需要1个非常简单的哈希表就能满足要求。由于字符(char)是1个长度为8的数据类型,因此总共有可能256 种可能。于是我们创建1个长度为256的数组,每个字母根据其ASCII码值作为数组的下标对应数组的对应项,而数组中存储的是每个字符对应的次数。这样我们就创建了1个大小为256,以字符ASCII码为键值的哈希表。

我们第1遍扫描这个数组时,每碰到1个字符,在哈希表中找到对应的项并将出现的次数增加1次。这样在进行第2次扫描时,就能直接从哈希表中得到每个字符出现的次数了。

参考代码如下:

///

// Find the first char which appears only once in a string

// Input: pString - the string

// Output: the first not repeating char if the string has, otherwise 0

///

char FirstNotRepeatingChar(char* pString)

{

// invalid input

if(!pString)

return 0;

// get a hash table, and initialize it

constinttableSize =256;

unsignedinthashTable[tableSize];

for(unsignedinti = 0; i<tableSize; ++ i)

hashTable[i] = 0;

// get the how many times each char appears in the string

char* pHashKey = pString;

while(*(pHashKey) != '\0')

hashTable[*(pHashKey++)] ++;

// find the first char which appears only once in a string

pHashKey = pString;

while(*pHashKey != '\0')

{

if(hashTable[*pHashKey] == 1)

return *pHashKey;

pHashKey++;

}

// if the string is empty

// or every char in the string appears at least twice

return 0;

}

(14) 圆圈中最后剩下的数字

题目:n个数字(0,1,…,n-1)形成1个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字(第1个为当前数字本身,第2个为当前数字的下1个数字)。当1个数字删除后,从被删除数字的下1个继续删除第m个数字。求出在这个圆圈中剩下的最后1个数字。

分析:既然题目有1个数字圆圈,很自然的想法是我们用1个数据结构来模拟这个圆圈。在常用的数据结构中,我们很容易想到用环形列表。我们可以创建1个总共有m个数字的环形列表,然后每次从这个列表中删除第m个元素。

在参考代码中,我们用STL中std::list来模拟这个环形列表。由于list并不是1个环形的结构,因此每次跌代器扫描到列表末尾的时候,要记得将跌代器移到列表的头部。这样就是按照1个圆圈的顺序来遍历这个列表了。

这种思路需要1个有n个结点的环形列表来模拟这个删除的过程,因此内存开销为O(n)。而且这种方法每删除1个数字需要m步运算,总共有n个数字,因此总的时间复杂度是O(mn)。当m和n都很大的时候,这种方法是很慢的。

接下来我们试着从数学上分析出1些规律。首先定义最初的n个数字(0,1,…,n-1)中最后剩下的数字是关于n和m的方程为f(n,m)。

在这n个数字中,第1个被删除的数字是m%n-1,为简单起见记为k。那么删除k之后的剩下n-1的数字为0,1,…,k-1,k+1,…,n-1,并且下1个开始计数的数字是k+1。相当于在剩下的序列中,k+1排到最前面,从而形成序列k+1,…,n-1,0,…k-1。该序列最后剩下的数字也应该是关于n和m的函数。由于这个序列的规律和前面最初的序列不1样(最初的序列是从0开始的连续序列),因此该函数不同于前面函数,记为f’(n-1,m)。最初序列最后剩下的数字f(n,m)1定是剩下序列的最后剩下数字f’(n-1,m),所以f(n,m)=f’(n-1,m)。

接下来我们将剩下的的这n-1个数字的序列k+1,…,n-1,0,…k-1作1个映射,映射的结果是形成1个从0到n-2的序列:

k+1    ->    0

k+2    ->    1

n-1    ->    n-k-2

0   ->    n-k-1

k-1   ->   n-2

将映射定义为p,则p(x)= (x-k-1)%n,即如果映射前的数字是x,则映射后的数字是(x-k-1)%n。对应的逆映射是p-1(x)=(x+k+1)%n。

由于映射之后的序列和最初的序列有同样的形式,都是从0开始的连续序列,因此仍然可以用函数f来表示,记为f(n-1,m)。根据我们的映射要求,映射之前的序列最后剩下的数字f’(n-1,m)= p-1 [f(n-1,m)]=[f(n-1,m)+k+1]%n。将k=m%n-1代入得到f(n,m)=f’(n-1,m)=[f(n-1,m)+m]%n。

经过上面复杂的分析,我们终于找到1个递归的公式。要得到n个数字的序列的最后剩下的数字,只需要得到n-1个数字的序列的最后剩下的数字,并可以依此类推。当n=1时,也就是序列中开始只有1个数字0,那么很显然最后剩下的数字就是0。我们将这种关系表示为:

0                  n=1

f(n,m)={

[f(n-1,m)+m]%n     n>1

尽管得到这个公式的分析过程非常复杂,但它用递归或者循环都很容易实现。最重要的是,这是1种时间复杂度为O(n),空间复杂度为O(1)的方法,因此无论在时间上还是空间上都优于前面的思路。

思路1的参考代码:

///

// n integers (0, 1, 、、、 n - 1) form a circle、 Remove the mth from

// the circle at every time、 Find the last number remaining

// Input: n - the number of integers in the circle initially

//        m - remove the mth number at every time

// Output: the last number remaining when the input is valid,

//         otherwise -1

///

int LastRemaining_Solution1(unsigned int n, unsigned int m)

{

// invalid input

if(n < 1 || m < 1)

return -1;

unsigned int i = 0;

// initiate a list with n integers (0, 1, 、、、 n - 1)

list<int> integers;

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

integers、push_back(i);

list<int>::iterator curinteger = integers、begin();

while(integers、size() > 1)

{

// find the mth integer、 Note that std::list is not a circle

// so we should handle it manually

for(int i = 1; i < m; ++ i)

{

curinteger ++;

if(curinteger == integers、end())

curinteger = integers、begin();

}

// remove the mth integer、 Note that std::list is not a circle

// so we should handle it manually

list<int>::iterator nextinteger = ++ curinteger;

if(nextinteger == integers、end())

nextinteger = integers、begin();

-- curinteger;

integers、erase(curinteger);

curinteger = nextinteger;

}

return *(curinteger);

}

思路二的参考代码:

///

// n integers (0, 1, 、、、 n - 1) form a circle、 Remove the mth from

// the circle at every time、 Find the last number remaining

// Input: n - the number of integers in the circle initially

//        m - remove the mth number at every time

// Output: the last number remaining when the input is valid,

//         otherwise -1

///

int LastRemaining_Solution2(int n, unsigned int m)

{

// invalid input

if(n <= 0 || m < 0)

return -1;

// if there are only one integer in the circle initially,

// of course the last remaining one is 0

int lastinteger = 0;

// find the last remaining one in the circle with n integers

for (int i = 2; i <= n; i ++)

lastinteger = (lastinteger + m) % i;

return lastinteger;

}

如果对两种思路的时间复杂度感兴趣的读者可以将n和m的值设的稍微大1点,比如十万这个数量级的数字,运行的时候就能明显感觉出这两种思路写出来的代码时间效率大不1样。

(15) 含有指针成员的类的拷贝

题目:下面是1个数组类的声明与实现。请分析这个类有什么问题,并针对存在的问题提出几种解决方案。

template<typename T> class Array

{

public:

Array(unsigned arraySize):data(0), size(arraySize)

{

if(size > 0)

data = new T[size];

}

~Array()

{

if(data) delete[] data;

}

void setValue(unsigned index, const T& value)

{

if(index < size)

data[index] = value;

}

T getValue(unsigned index) const

{

if(index < size)

return data[index];

else

return T();

}

private:

T* data;

unsigned size;

};

分析:我们注意在类的内部封装了用来存储数组数据的指针。软件存在的大部分问题通常都可以归结指针的不正确处理。

这个类只提供了1个构造函数,而没有定义构造拷贝函数和重载拷贝运算符函数。当这个类的用户按照下面的方式声明并实例化该类的1个实例

Array A(10);

Array B(A);

或者按照下面的方式将该类的1个实例赋值给另外1个实例

Array A(10);

Array B(10);

B=A;

编译器将调用其自动生成的构造拷贝函数或者拷贝运算符的重载函数。在编译器生成的缺省的构造拷贝函数和拷贝运算符的重载函数,对指针实行的是按位拷贝,仅仅只是拷贝指针的地址,而不会拷贝指针的内容。因此在执行完前面的代码之后,A、data和B、data指向的同1地址。当A或者B中任意1个结束其生命周期调用析构函数时,会删除data。由于他们的data指向的是同1个地方,两个实例的data都被删除了。但另外1个实例并不知道它的data已经被删除了,当企图再次用它的data的时候,程序就会不可避免地崩溃。

由于问题出现的根源是调用了编译器生成的缺省构造拷贝函数和拷贝运算符的重载函数。1个最简单的办法就是禁止使用这两个函数。于是我们可以将这两个函数声明为私有函数,如果类的用户企图调用这两个函数,将不能通过编译。实现的代码如下:

private:

Array(const Array& copy);

const Array& operator = (const Array& copy);

最初的代码存在问题是因为不同实例的data指向的同1地址,删除1个实例的data会将另外1个实例的data也同时删除。因此我们还可以让构造拷贝函数或者拷贝运算符的重载函数拷贝的不只是地址,而是数据。由于我们重新存储了1份数据,这样1个实例删除的时候,对另外1个实例没有影响。这种思路我们称之为深度拷贝。实现的代码如下:

public:

Array(const Array& copy):data(0), size(copy、size)

{

if(size > 0)

{

data = new T[size];

for(int i = 0; i < size; ++ i)

setValue(i, copy、getValue(i));

}

}

const Array& operator = (const Array& copy)

{

if(this == ©)

return *this;

if(data != NULL)

{

delete []data;

data = NULL;

}

size = copy、size;

if(size > 0)

{

data = new T[size];

for(int i = 0; i < size; ++ i)

setValue(i, copy、getValue(i));

}

}

为了防止有多个指针指向的数据被多次删除,我们还可以保存究竟有多少个指针指向该数据。只有当没有任何指针指向该数据的时候才可以被删除。这种思路通常被称之为引用计数技术。在构造函数中,引用计数初始化为1;每当将这个实例赋值给其他实例或者以参数传给其他实例的构造拷贝函数的时候,引用计数加1,因为这意味着又多了1个实例指向它的data;每次需要调用析构函数或者需要将data赋值为其他数据的时候,引用计数要减1,因为这意味着指向它的data的指针少了1个。当引用计数减少到0的时候,data已经没有任何实例指向它了,这个时候就可以安全地删除。实现的代码如下:

public:

Array(unsigned arraySize)

:data(0), size(arraySize), count(new unsigned int)

{

*count = 1;

if(size > 0)

data = new T[size];

}

Array(const Array& copy)

: size(copy、size), data(copy、data), count(copy、count)

{

++ (*count);

}

~Array()

{

Release();

}

const Array& operator = (const Array& copy)

{

if(data == copy、data)

return *this;

Release();

data = copy、data;

size = copy、size;

count = copy、count;

++(*count);

}

private:

void Release()

{

--(*count);

if(*count == 0)

{

if(data)

{

delete []data;

data = NULL;

}

delete count;

count = 0;

}

}

unsigned int *count;

(16) O(logn)求Fibonacci数列

题目:定义Fibonacci数列如下:

/  0                      n=0

f(n)=      1                      n=1

\  f(n-1)+f(n-2)          n=2

输入n,用最快的方法求该数列的第n项。

分析:在很多C语言教科书中讲到递归函数的时候,都会用Fibonacci作为例子。因此很多程序员对这道题的递归解法非常熟悉,看到题目就能写出如下的递归求解的代码。

///

// Calculate the nth item of Fibonacci Series recursively

///

long long Fibonacci_Solution1(unsigned int n)

{

int result[2] = {0, 1};

if(n < 2)

return result[n];

return Fibonacci_Solution1(n - 1) + Fibonacci_Solution1(n - 2);

}

但是,教科书上反复用这个题目来讲解递归函数,并不能说明递归解法最适合这道题目。我们以求解f(10)作为例子来分析递归求解的过程。要求得f(10),需要求得f(9)和f(8)。同样,要求得f(9),要先求得f(8)和f(7)……我们用树形结构来表示这种依赖关系

f(10)

/        \

f(9)         f(8)

/     \       /    \

f(8)     f(7)  f(6)   f(5)

/   \     /   \

f(7)  f(6)  f(6) f(5)

我们不难发现在这棵树中有很多结点会重复的,而且重复的结点数会随着n的增大而急剧增加。这意味这计算量会随着n的增大而急剧增大。事实上,用递归方法计算的时间复杂度是以n的指数的方式递增的。大家可以求Fibonacci的第100项试试,感受1下这样递归会慢到什么程度。在我的机器上,连续运行了1个多小时也没有出来结果。

其实改进的方法并不复杂。上述方法之所以慢是因为重复的计算太多,只要避免重复计算就行了。比如我们可以将已经得到的数列中间项保存起来,如果下次需要计算的时候我们先查找1下,如果前面已经计算过了就不用再次计算了。

更简单的办法是从下往上计算,首先根据f(0)和f(1)算出f(2),在根据f(1)和f(2)算出f(3)……依此类推就可以算出第n项了。很容易理解,这种思路的时间复杂度是O(n)。

///

// Calculate the nth item of Fibonacci Series iteratively

///

long long Fibonacci_Solution2(unsigned n)

{

int result[2] = {0, 1};

if(n < 2)

return result[n];

long long  fibNMinusOne = 1;

long long  fibNMinusTwo = 0;

long long  fibN = 0;

for(unsigned int i = 2; i <= n; ++ i)

{

fibN = fibNMinusOne + fibNMinusTwo;

fibNMinusTwo = fibNMinusOne;

fibNMinusOne = fibN;

}

return fibN;

}

这还不是最快的方法。下面介绍1种时间复杂度是O(logn)的方法。在介绍这种方法之前,先介绍1个数学公式:

{f(n), f(n-1), f(n-1), f(n-2)} ={1, 1, 1,0}n-1

(注:{f(n+1), f(n), f(n), f(n-1)}表示1个矩阵。在矩阵中第1行第1列是f(n+1),第1行第2列是f(n),第2行第1列是f(n),第2行第2列是f(n-1)。)

有了这个公式,要求得f(n),我们只需要求得矩阵{1, 1, 1,0}的n-1次方,因为矩阵{1, 1, 1,0}的n-1次方的结果的第1行第1列就是f(n)。这个数学公式用数学归纳法不难证明。感兴趣的朋友不妨自己证明1下。

现在的问题转换为求矩阵{1, 1, 1, 0}的乘方。如果简单第从0开始循环,n次方将需要n次运算,并不比前面的方法要快。但我们可以考虑乘方的如下性质:

/  an/2*an/2                      n为偶数时

an=

\  a(n-1)/2*a(n-1)/2            n为奇数时

要求得n次方,我们先求得n/2次方,再将n/2的结果平方1下。如果将求n次方的问题看成1个大问题,将求n/2看成1个较小的问题。这种将大问题分解成1个或多个小问题的思路我们称之为分治法。这样求n次方就只需要logn次运算了。

实现这种方式时,首先需要定义1个2×2的矩阵,并且定义好矩阵的乘法以及乘方运算。当这些运算定义好了之后,剩下的事情就变得非常简单。完整的实现代码如下所示。

#include <cassert>

///

// A 2 by 2 matrix

///

struct Matrix2By2

{

Matrix2By2

(

long long m00 = 0,

long long m01 = 0,

long long m10 = 0,

long long m11 = 0

)

:m_00(m00), m_01(m01), m_10(m10), m_11(m11)

{

}

long long m_00;

long long m_01;

long long m_10;

long long m_11;

};

///

// Multiply two matrices

// Input: matrix1 - the first matrix

//        matrix2 - the second matrix

//Output: the production of two matrices

///

Matrix2By2 MatrixMultiply

(

const Matrix2By2& matrix1,

const Matrix2By2& matrix2

)

{

return Matrix2By2(

matrix1、m_00 * matrix2、m_00 + matrix1、m_01 * matrix2、m_10,

matrix1、m_00 * matrix2、m_01 + matrix1、m_01 * matrix2、m_11,

matrix1、m_10 * matrix2、m_00 + matrix1、m_11 * matrix2、m_10,

matrix1、m_10 * matrix2、m_01 + matrix1、m_11 * matrix2、m_11);

}

///

// The nth power of matrix

// 1  1

// 1  0

///

Matrix2By2 MatrixPower(unsigned int n)

{

assert(n > 0);

Matrix2By2 matrix;

if(n == 1)

{

matrix = Matrix2By2(1, 1, 1, 0);

}

else if(n % 2 == 0)

{

matrix = MatrixPower(n / 2);

matrix = MatrixMultiply(matrix, matrix);

}

else if(n % 2 == 1)

{

matrix = MatrixPower((n - 1) / 2);

matrix = MatrixMultiply(matrix, matrix);

matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0));

}

return matrix;

}

///

// Calculate the nth item of Fibonacci Series using devide and conquer

///

long long Fibonacci_Solution3(unsigned int n)

{

int result[2] = {0, 1};

if(n < 2)

return result[n];

Matrix2By2 PowerNMinus2 = MatrixPower(n - 1);

return PowerNMinus2、m_00;

}

(17) 将string转换成整数

题目:输入1个表示整数的string,将该string转换成整数并输出。示例输入string"345",则输出整数345。

分析:这道题尽管不是很难,学过C/C++语言1般都能实现基本功能,但不同程序员就这道题写出的代码有很大区别,可以说这道题能够很好地反应出程序员的思维和编程习惯,因此已经被包括微软在内的多家公司用作面试题。建议读者在往下看之前自己先编写代码,再比较自己写的代码和下面的参考代码有哪些不同。

首先我们分析如何完成基本功能,即如何将表示整数的string正确地转换成整数。还是以"345"作为例子。当我们扫描到string的第1个字符'3'时,我们不知道后面还有多少位,仅仅知道这是第1位,因此此时得到的数字是3。当扫描到第2个数字'4'时,此时我们已经知道前面已经1个3了,再在后面加上1个数字4,那前面的3相当于30,因此得到的数字是3*10+4=34。接着我们又扫描到字符'5',我们已经知道了'5'的前面已经有了34,由于后面要加上1个5,前面的34就相当于340了,因此得到的数字就是34*10+5=345。

分析到这里,我们不能得出1个转换的思路:每扫描到1个字符,我们将在之前得到的数字乘以10再加上当前字符表示的数字。这个思路用循环不难实现。

由于整数可能不仅仅之含有数字,还有可能以'+'或者'-'开头,表示整数的正负。因此我们需要将这个string的第1个字符做特殊处理。如果第1个字符是'+'号,则不需要做任何操作;如果第1个字符是'-'号,则表明这个整数是个负数,在最后的时候我们要将得到的数值变成负数。

接着我们试着处理非法输入。由于输入的是指针,在使用指针之前,我们要做的第1件是判断这个指针是不是为空。如果试着去访问空指针,将不可避免地导致程序崩溃。另外,输入的string中可能含有不是数字的字符。每当碰到这些非法的字符,我们就没有必要再继续转换。最后1个需要考虑的问题是溢出问题。由于输入的数字是以string的形式输入,因此有可能输入1个很大的数字转换之后会超过能够表示的最大的整数而溢出。

现在已经分析的差不多了,开始考虑编写代码。首先我们考虑如何声明这个函数。由于是将string转换成整数,很自然我们想到:

int StrToInt(const char* str);

这样声明看起来没有问题。但当输入的string是1个空指针或者含有非法的字符时,应该返回什么值呢?0怎么样?那怎么区分非法输入和string本身就是”0”这两种情况呢?

接下来我们考虑另外1种思路。我们可以返回1个布尔值来指示输入是否有效,而将转换后的整数放到参数列表中以引用或者指针的形式传入。于是我们就可以声明如下:

bool StrToInt(const char *str, int& num);

这种思路解决了前面的问题。但是这个函数的用户使用这个函数的时候会觉得不是很方便,因为他不能直接将得到的整数赋值给其他整形变脸,显得不够直观。

前面的第1种声明就很直观。如何在保证直观的前提下当碰到非法输入的时候通知用户呢?1种解决方案就是定义1个全局变量,每当碰到非法输入的时候,就标记该全局变量。用户在调用这个函数之后,就可以检验该全局变量来判断转换是不是成功。

下面我们写出完整的实现代码。参考代码:

enum Status {kValid = 0, kInvalid};

int g_nStatus = kValid;

///

// Convert a string into an integer

///

int StrToInt(const char* str)

{

g_nStatus = kInvalid;

longlongnum = 0;

if(str != NULL)

{

const char* digit = str;

// the first char in the string maybe '+' or '-'

bool minus = false;

if(*digit == '+')

digit ++;

else if(*digit == '-')

{

digit ++;

minus = true;

}

// the remaining chars in the string

while(*digit != '\0')

{

if(*digit >= '0' && *digit <= '9')

{

num = num * 10 + (*digit - '0');

// overflow

if(num>std::numeric_limits<int>::max())

{

num = 0;

break;

}

digit++;

}

// if the char is not a digit, invalid input

else

{

num = 0;

break;

}

}

if(*digit == '\0')

{

g_nStatus = kValid;

if(minus)

num = 0 - num;

}

}

return static_cast<int>(num);

}

讨论:在参考代码中,我选用的是第1种声明方式。不过在面试时,我们可以选用任意1种声明方式进行实现。但当面试官问我们选择的理由时,我们要对两者的优缺点进行评价。第1种声明方式对用户而言非常直观,但使用了全局变量,不够优雅;而第2种思路是用返回值来表明输入是否合法,在很多API中都用这种方法,但该方法声明的函数使用起来不够直观。

最后值得1提的是,在C语言提供的库函数中,函数atoi能够将string转换整数。它的声明是int atoi(const char *str)。该函数就是用1个全局变量来标志输入是否合法的。

(18) 用两个栈实现队列

题目:某队列的声明如下:

template<typename T> class CQueue

{

public:

CQueue() {}

~CQueue() {}

void appendTail(const T& node);  // append a element to tail

void deleteHead();               // remove a element from head

private:

T>m_stack1;

T>m_stack2;

};

分析:从上面的类的声明中,我们发现在队列中有两个栈。因此这道题实质上是要求我们用两个栈来实现1个队列。相信大家对栈和队列的基本性质都非常了解了:栈是1种后入先出的数据容器,因此对队列进行的插入和删除操作都是在栈顶上进行;队列是1种先入先出的数据容器,我们总是将新元素插入到队列的尾部,而从队列的头部删除元素。

我们通过1个具体的例子来分析往该队列插入和删除元素的过程。首先插入1个元素a,不妨将先它插入到m_stack1。这个时候m_stack1中的元素有{a},m_stack2为空。再插入两个元素b和c,还是插入到m_stack1中,此时m_stack1中的元素有{a,b,c},m_stack2中仍然是空的。

这个时候我们试着从队列中删除1个元素。按照队列先入先出的要求,由于a比b、c先插入到队列中,这次被删除的元素应该是a。元素a存储在m_stack1中,但并不在栈顶上,因此不能直接进行删除。注意到m_stack2我们还1直没有使用过,现在是让m_stack2起作用的时候了。如果我们将m_stack1中的元素逐个pop出来并push进入m_stack2,元素在m_stack2中的顺序正好和原来在m_stack1中的顺序相反。因此经过两次pop和push之后,m_stack1为空,而m_stack2中的元素是{c,b,a}。这个时候就可以pop出m_stack2的栈顶a了。pop之后的m_stack1为空,而m_stack2的元素为{c,b},其中b在栈顶。

这个时候如果我们还想继续删除应该怎么办呢?在剩下的两个元素中b和c,b比c先进入队列,因此b应该先删除。而此时b恰好又在栈顶上,因此可以直接pop出去。这次pop之后,m_stack1中仍然为空,而m_stack2为{c}。

从上面的分析我们可以总结出删除1个元素的步骤:当m_stack2中不为空时,在m_stack2中的栈顶元素是最先进入队列的元素,可以pop出去。如果m_stack2为空时,我们将m_stack1中的元素逐个pop出来并push进入m_stack2。由于先进入队列的元素被压到m_stack1的底端,经过pop和push之后就处于m_stack2的顶端了,又可以直接pop出去。

接下来我们再插入1个元素d。我们是不是还可以将它push进m_stack1?这样会不会有问题呢?我们说不会有问题。因为在删除元素的时候,如果m_stack2中不为空,处于m_stack2中的栈顶元素是最先进入队列的,可以直接pop;如果m_stack2为空,我们将m_stack1中的元素pop出来并push进入m_stack2。由于m_stack2中元素的顺序和m_stack1相反,最先进入队列的元素还是处于m_stack2的栈顶,仍然可以直接pop。不会出现任何矛盾。

我们用1个表来总结1下前面的例子执行的步骤:

操作

m_stack1

m_stack2

append a

{a}

{}

append b

{a,b}

{}

append c

{a,b,c}

{}

delete head

{}

{b,c}

delete head

{}

{c}

append d

{d}

{c}

delete head

{d}

{}

总结完push和pop对应的过程之后,我们可以开始动手写代码了。参考代码如下:

///

// Append a element at the tail of the queue

///

template<typename T> void CQueue<T>::appendTail(const T& element)

{

// push the new element into m_stack1

m_stack1、push(element);

}

///

// Delete the head from the queue

///

template<typename T> void CQueue<T>::deleteHead()

{

// if m_stack2is empty,and there are some

//elements inm_stack1, push them in m_stack2

if(m_stack2、size()<= 0)

{

while(m_stack1、size()>0)

{

T&data =m_stack1、top();

m_stack1、pop();

m_stack2、push(data);

}

}

// push theelement into m_stack2

assert(m_stack2、size()>0);

m_stack2、pop();

}

扩展:这道题是用两个栈实现1个队列。反过来能不能用两个队列实现1个栈?如果可以,该如何实现?

(19) 反转链表

题目:输入1个链表的头结点,反转该链表,并返回反转后链表的头结点。链表结点定义如下:

struct ListNode

{

int       m_nKey;

ListNode* m_pNext;

};

分析:这是1道广为流传的微软面试题。由于这道题能够很好的反应出程序员思维是否严密,在微软之后已经有很多公司在面试时采用了这道题。

为了正确地反转1个链表,需要调整指针的指向。与指针操作相关代码总是容易出错的,因此最好在动手写程序之前作全面的分析。在面试的时候不急于动手而是1开始做仔细的分析和设计,将会给面试官留下很好的印象,因为在实际的软件开发中,设计的时间总是比写代码的时间长。与其很快地写出1段漏洞百出的代码,远不如用较多的时间写出1段健壮的代码。

为了将调整指针这个复杂的过程分析清楚,我们可以借助图形来直观地分析。假设下图中l、m和n是三个相邻的结点:

aßbß…ßl  mànà…

假设经过若干操作,我们已经将结点l之前的指针调整完毕,这些结点的m_pNext指针都指向前面1个结点。现在我们遍历到结点m。当然,我们需要将调整结点的m_pNext指针让它指向结点l。但注意1旦调整了指针的指向,链表就断开了,如下图所示:

aßbß…lßm  nà…

因为已经没有指针指向结点n,我们没有办法再遍历到结点n了。因此为了避免链表断开,我们需要在调整m的m_pNext之前要将n保存下来。

接下来我们试着找到反转后链表的头结点。不难分析出反转后链表的头结点是原始链表的尾位结点。什么结点是尾结点?就是m_pNext为空指针的结点。

基于上述分析,我们不难写出如下代码:

///

// Reverse a list iteratively

// Input: pHead - the head of the original list

// Output: the head of the reversed head

///

ListNode* ReverseIteratively(ListNode* pHead)

{

ListNode* pReversedHead = NULL;

ListNode* pNode = pHead;

ListNode* pPrev = NULL;

while(pNode != NULL)

{

// get the next node, and save it at pNext

ListNode* pNext = pNode->m_pNext;

// if the next node is null, the currect is the end of original

// list, and it's the head of the reversed list

if(pNext == NULL)

pReversedHead = pNode;

// reverse the linkage between nodes

pNode->m_pNext = pPrev;

// move forward on the the list

pPrev = pNode;

pNode = pNext;

}

return pReversedHead;

}

扩展:本题也可以递归实现。感兴趣的读者请自己编写递归代码。

(20) 最长公共子串

题目:如果string1的所有字符按其在string中的顺序出现在另外1个string二中,则string1称之为string二的子串。注意,并不要求子串(string1)的字符必须连续出现在string二中。请编写1个函数,输入两个string,求它们的最长公共子串,并打印出最长公共子串。

示例:输入两个stringBDCABA和ABCBDAB,stringBCBA和BDAB都是是它们的最长公共子串,则输出它们的长度4,并打印任意1个子串。

分析:求最长公共子串(Longest Common Subsequence, LCS)是1道非常经典的动态规划题,因此1些重视算法的公司像MicroStrategy都将它当作面试题。

完整介绍动态规划将需要很长的篇幅,因此我不打算在此全面讨论动态规划相关的概念,只集中对LCS直接相关内容作讨论。如果对动态规划不是很熟悉,请参考相关算法书比如算法讨论。

先介绍LCS问题的性质:记Xm={x0, x1,…xm-1}和Yn={y0,y1,…,yn-1}为两个string,而Zk={z0,z1,…zk-1}是它们的LCS,则:

1、       如果xm-1=yn-1,那么zk-1=xm-1=yn-1,并且Zk-1是Xm-1和Yn-1的LCS;

2、       如果xm-1≠yn-1,那么当zk-1≠xm-1时Z是Xm-1和Y的LCS;

3、       如果xm-1≠yn-1,那么当zk-1≠yn-1时Z是Yn-1和X的LCS;

下面简单证明1下这些性质:

1、       如果zk-1≠xm-1,那么我们可以将xm-1(yn-1)加到Z中得到Z’,这样就得到X和Y的1个长度为k+1的公共子串Z’。这就与长度为k的Z是X和Y的LCS相矛盾了。因此1定有zk-1=xm-1=yn-1。

既然zk-1=xm-1=yn-1,那如果我们删除zk-1(xm-1、yn-1)得到的Zk-1,Xm-1和Yn-1,显然Zk-1是Xm-1和Yn-1的1个公共子串,现在我们证明Zk-1是Xm-1和Yn-1的LCS。用反证法不难证明。假设有Xm-1和Yn-1有1个长度超过k-1的公共子串W,那么我们将加到W中得到W’,那W’就是X和Y的公共子串,并且长度超过k,这就和已知条件相矛盾了。

2、       还是用反证法证明。假设Z不是Xm-1和Y的LCS,则存在1个长度超过k的W是Xm-1和Y的LCS,那W肯定也X和Y的公共子串,而已知条件中X和Y的公共子串的最大长度为k。矛盾。

3、       证明同2。

有了上面的性质,我们可以得出如下的思路:求两stringXm={x0, x1,…xm-1}和Yn={y0,y1,…,yn-1}的LCS,如果xm-1=yn-1,那么只需求得Xm-1和Yn-1的LCS,并在其后添加xm-1(yn-1)即可;如果xm-1≠yn-1,我们分别求得Xm-1和Y的LCS和Yn-1和X的LCS,并且这两个LCS中较长的1个为X和Y的LCS。

如果我们记stringXi和Yj的LCS的长度为c[i,j],我们可以递归地求c[i,j]:

/      0                               if i<0 or j<0

c[i,j]=          c[i-1,j-1]+1                    if i,j>=0 and xi=xj

\       max(c[i,j-1],c[i-1,j]           if i,j>=0 and xi≠xj

上面的公式用递归函数不难求得。但从前面求Fibonacci第n项(本面试题系列第16题)的分析中我们知道直接递归会有很多重复计算,我们用从底向上循环求解的思路效率更高。

为了能够采用循环求解的思路,我们用1个矩阵(参考代码中的LCS_length)保存下来当前已经计算好了的c[i,j],当后面的计算需要这些数据时就可以直接从矩阵读取。另外,求取c[i,j]可以从c[i-1,j-1] 、c[i,j-1]或者c[i-1,j]三个方向计算得到,相当于在矩阵LCS_length中是从c[i-1,j-1],c[i,j-1]或者c[i-1,j]的某1个各自移动到c[i,j],因此在矩阵中有三种不同的移动方向:向左、向上和向左上方,其中只有向左上方移动时才表明找到LCS中的1个字符。于是我们需要用另外1个矩阵(参考代码中的LCS_direction)保存移动的方向。

参考代码如下:

#include "string、h"

// directions of LCS generation

enum decreaseDir {kInit = 0, kLeft, kUp, kLeftUp};

/

// Get the length of two strings' LCSs, and print one of the LCSs

// Input: pStr1         - the first string

//        pStr2         - the second string

// Output: the length of two strings' LCSs

/

int LCS(char* pStr1, char* pStr2)

{

if(!pStr1 || !pStr2)

return 0;

size_t length1 = strlen(pStr1);

size_t length2 = strlen(pStr2);

if(!length1 || !length2)

return 0;

size_t i, j;

// initiate the length matrix

int **LCS_length;

LCS_length = (int**)(new int[length1]);

for(i = 0; i < length1; ++ i)

LCS_length[i] = (int*)new int[length2];

for(i = 0; i < length1; ++ i)

for(j = 0; j < length2; ++ j)

LCS_length[i][j] = 0;

// initiate the direction matrix

int **LCS_direction;

LCS_direction = (int**)(new int[length1]);

for( i = 0; i < length1; ++ i)

LCS_direction[i] = (int*)new int[length2];

for(i = 0; i < length1; ++ i)

for(j = 0; j < length2; ++ j)

LCS_direction[i][j] = kInit;

for(i = 0; i < length1; ++ i)

{

for(j = 0; j < length2; ++ j)

{

if(i == 0 || j == 0)

{

if(pStr1[i] == pStr2[j])

{

LCS_length[i][j] = 1;

LCS_direction[i][j] = kLeftUp;

}

else

LCS_length[i][j] = 0;

}

// a char of LCS is found,

// it comes from the left up entry in the direction matrix

else if(pStr1[i] == pStr2[j])

{

LCS_length[i][j] = LCS_length[i - 1][j - 1] + 1;

LCS_direction[i][j] = kLeftUp;

}

// it comes from the up entry in the direction matrix

else if(LCS_length[i - 1][j] > LCS_length[i][j - 1])

{

LCS_length[i][j] = LCS_length[i - 1][j];

LCS_direction[i][j] = kUp;

}

// it comes from the left entry in the direction matrix

else

{

LCS_length[i][j] = LCS_length[i][j - 1];

LCS_direction[i][j] = kLeft;

}

}

}

LCS_Print(LCS_direction, pStr1, pStr2, length1 - 1, length2 - 1);

return LCS_length[length1 - 1][length2 - 1];

}

/

// Print a LCS for two strings

// Input: LCS_direction - a 2d matrix which records the direction of

//                        LCS generation

//        pStr1         - the first string

//        pStr2         - the second string

//        row           - the row index in the matrix LCS_direction

//        col           - the column index in the matrix LCS_direction

/

void LCS_Print(int **LCS_direction,

char* pStr1, char* pStr2,

size_t row, size_t col)

{

if(pStr1 == NULL || pStr2 == NULL)

return;

size_t length1 = strlen(pStr1);

size_t length2 = strlen(pStr2);

if(length1 == 0 || length2 == 0 || !(row < length1 && col < length2))

return;

// kLeftUp implies a char in the LCS is found

if(LCS_direction[row][col] == kLeftUp)

{

if(row > 0 && col > 0)

LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col - 1);

// print the char

printf("%c", pStr1[row]);

}

else if(LCS_direction[row][col] == kLeft)

{

// move to the left entry in the direction matrix

if(col > 0)

LCS_Print(LCS_direction, pStr1, pStr2, row, col - 1);

}

else if(LCS_direction[row][col] == kUp)

{

// move to the up entry in the direction matrix

if(row > 0)

LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col);

}

}

扩展:如果题目改成求两个string的最长公共子string,应该怎么求?子string的定义和子串的定义类似,但要求是连续分布在其他string中。比如输入两个stringBDCABA和ABCBDAB的最长公共string有BD和AB,它们的长度都是2。

(21) 左旋转string

题目:定义string的左旋转操作:将string前面的若干个字符移动到string的尾部。如将stringabcdef左旋转2位得到stringcdefab。请实现string左旋转的函数。要求时间对长度为n的string操作的复杂度为O(n),辅助内存为O(1)。

分析:如果不考虑时间和空间复杂度的限制,最简单的方法莫过于将这道题看成是将string分成前后两部分,通过旋转操作将这两个部分交换位置。于是我们可以新开辟1块长度为n+1的辅助空间,将原string后半部分拷贝到新空间的前半部分,在将原string的前半部分拷贝到新空间的后半部分。不难看出,这种思路的时间复杂度是O(n),需要的辅助空间也是O(n)。

接下来的1种思路可能要稍微麻烦1点。我们假设将string左旋转m位。于是我们先将第0个字符保存起来,将第m个字符放到第0个的位置,在将第2m个字符放到第m个的位置…依次类推,1直移动到最后1个可以移动字符,最后在将原来的第0个字符放到刚才移动的位置上。接着将第1个字符保存起来,将第m+1个元素移动到第1个位置…重复前面处理第0个字符的步骤,直到处理完前面的m个字符。

该思路还是比较容易理解,但当string的长度n不是m的整数倍的时候,写程序会有些麻烦,感兴趣的朋友可以自己试1下。由于下面还要介绍更好的方法,这种思路的代码我就不提供了。

我们还是将string看成有两段组成的,记位XY。左旋转相当于要将stringXY变成YX。我们先在string上定义1种翻转的操作,就是翻转string中字符的先后顺序。将X翻转后记为XT。显然有(XT)T=X。

我们首先对X和Y两段分别进行翻转操作,这样就能得到XTYT。接着再对XTYT进行翻转操作,得到(XTYT)T=(YT)T(XT)T=YX。正好是我们期待的结果。

分析到这里我们再回到原来的题目。我们要做的仅仅是将string分成两段,第1段为前面m个字符,其余的字符分到第2段。再定义1个翻转string的函数,按照前面的步骤翻转三次就行了。时间复杂度和空间复杂度都合乎要求。

参考代码如下:

#include "string、h"

///

// Move the first n chars in a string to its end

///

char* LeftRotateString(char* pStr, unsigned int n)

{

if(pStr != NULL)

{

int nLength = static_cast<int>(strlen(pStr));

if(nLength > 0 || n == 0 || n > nLength)

{

char* pFirstStart = pStr;

char* pFirstEnd = pStr + n - 1;

char* pSecondStart = pStr + n;

char* pSecondEnd = pStr + nLength - 1;

// reverse the first part of the string

ReverseString(pFirstStart, pFirstEnd);

// reverse the second part of the strint

ReverseString(pSecondStart, pSecondEnd);

// reverse the whole string

ReverseString(pFirstStart, pSecondEnd);

}

}

return pStr;

}

///

// Reverse the string between pStart and pEnd

///

void ReverseString(char* pStart, char* pEnd)

{

if(pStart == NULL || pEnd == NULL)

{

while(pStart <= pEnd)

{

char temp = *pStart;

*pStart = *pEnd;

*pEnd = temp;

pStart ++;

pEnd --;

}

}

}

(22) 整数的二进制表示中1的个数

题目:输入1个整数,求该整数的二进制表达中有多少个1。示例输入10,由于其二进制表示为1010,有两个1,因此输出2。

分析:这是1道很基本的考查位运算的面试题。包括微软在内的很多公司都曾采用过这道题。

1个很基本的想法是,我们先判断整数的最右边1位是不是1。接着将整数右移1位,原来处于右边第2位的数字现在被移到第1位了,再判断是不是1。这样每次移动1位,直到这个整数变成0为止。现在的问题变成怎样判断1个整数的最右边1位是不是1了。很简单,如果它和整数1作与运算。由于1除了最右边1位以外,其他所有位都为0。因此如果与运算的结果为1,表示整数的最右边1位是1,否则是0。

得到的代码如下:

///

// Get how many 1s in an integer's binary expression

///

int NumberOf1_Solution1(int i)

{

int count = 0;

while(i)

{

if(i & 1)

count ++;

i = i >> 1;

}

return count;

}

可能有读者会问,整数右移1位在数学上是和除以2是等价的。那可不可以将上面的代码中的右移运算符换成除以2呢?答案是最好不要换成除法。因为除法的效率比移位运算要低的多,在实际编程中如果可以应尽可能地用移位运算符代替乘除法。

这个思路当输入i是正数时没有问题,但当输入的i是1个负数时,不但不能得到正确的1的个数,还将导致死循环。以负数0x80000000为例,右移1位的时候,并不是简单地将最高位的1移到第2位变成0x40000000,而是0xC0000000。这是因为移位前是个负数,仍然要保证移位后是个负数,因此移位后的最高位会设为1。如果1直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环。

为了避免死循环,我们可以不右移输入的数字i。首先i和1做与运算,判断i的最低位是不是为1。接着将1左移1位得到2,再和i做与运算,就能判断i的次高位是不是1……这样反复左移,每次都能判断i的其中1位是不是1。基于此,我们得到如下代码:

///

// Get how many 1s in an integer's binary expression

///

int NumberOf1_Solution2(int i)

{

int count = 0;

unsigned int flag = 1;

while(flag)

{

if(i & flag)

count ++;

flag = flag << 1;

}

return count;

}

另外1种思路是如果1个整数不为0,那么这个整数至少有1位是1。如果我们将这个整数减去1,那么原来处在整数最右边的1就会变成0,原来在1后面的所有的0都会变成1。其余的所有位将不受到影响。举个例子:1个二进制数1100,从右边数起的第三位是处于最右边的1个1。减去1后,第三位变成0,它后面的两位0变成1,而前面的1保持不变,因此得到结果是1011。

我们发现减1的结果是将从最右边1个1开始的所有位都取反了。这个时候如果我们再将原来的整数和减去1之后的结果做与运算,从原来整数最右边1个1那1位开始所有位都会变成0。如1100&1011=1000。也就是说,将1个整数减去1,再和原整数做与运算,会将该整数最右边1个1变成0。那么1个整数的二进制有多少个1,就可以进行多少次这样的操作。

这种思路对应的代码如下:

///

// Get how many 1s in an integer's binary expression

///

int NumberOf1_Solution3(int i)

{

int count = 0;

while (i)

{

++ count;

i = (i - 1) & i;

}

return count;

}

扩展:如何用1个语句判断1个整数是不是二的整数次幂?

(23) 跳台阶问题

题目:1个台阶总共有n级,如果1次可以跳1级,也可以跳2级。求总共有多少总跳法,并分析算法的时间复杂度。

分析:这道题最近经常出现,包括MicroStrategy等比较重视算法的公司都曾先后选用过个这道题作为面试题或者笔试题。

首先我们考虑最简单的情况。如果只有1级台阶,那显然只有1种跳法。如果有2级台阶,那就有两种跳的方法了:1种是分两次跳,每次跳1级;另外1种就是1次跳2级。

现在我们再来讨论1般情况。我们将n级台阶时的跳法看成是n的函数,记为f(n)。当n>2时,第1次跳的时候就有两种不同的选择:1是第1次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);另外1种选择是第1次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。因此n级台阶时的不同跳法的总数f(n)=f(n-1)+(f-2)。

我们将上面的分析用1个公式总结如下:

/  1                          n=1

f(n)=      2                          n=2

\  f(n-1)+(f-2)               n>2

分析到这里,相信很多人都能看出这就是我们熟悉的Fibonacci序列。至于怎么求这个序列的第n项,请参考本面试题系列第16题,这里就不在赘述了。

(24) 栈的push、pop序列

题目:输入两个整数序列。其中1个序列表示栈的push顺序,判断另1个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。

比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是1个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。

分析:这到题除了考查对栈这1基本数据结构的理解,还能考查我们的分析能力。

这道题的1个很直观的想法就是建立1个辅助栈,每次push的时候就将1个整数push进入这个辅助栈,同样需要pop的时候就将该栈的栈顶整数pop出来。

我们以前面的序列4、5、3、2、1为例。第1个希望被pop出来的数字是4,因此4需要先push到栈里面。由于push的顺序已经由push序列确定了,也就是在将4 push进栈之前,数字1,2,3都需要push到栈里面。此时栈里的包含4个数字,分别是1,2,3,4,其中4位于栈顶。将4 pop出栈后,剩下三个数字1,2,3。接下来希望被pop的是5,由于仍然不是栈顶数字,我们接着在push序列中4以后的数字中寻找。找到数字5后再1次push进栈,这个时候5就是位于栈顶,可以被pop出来。接下来希望被pop的三个数字是3,2,1。每次操作前都位于栈顶,直接pop即可。

再来看序列4、3、5、1、2。pop数字4的情况和前面1样。将4 pop出来之后,3位于栈顶,直接pop。接下来希望pop的数字是5,由于5不是栈顶数字,我们到push序列中没有被push进栈的数字中去搜索该数字,幸运的时候能够找到5,于是将5 push进入栈。此时pop 5之后,栈内包含两个数字1、2,其中2位于栈顶。这个时候希望pop的数字是1,由于不是栈顶数字,我们需要到push序列中还没有被push进栈的数字中去搜索该数字。但此时push序列中所有数字都已被push进入栈,因此该序列不可能是1个pop序列。

也就是说,如果我们希望pop的数字正好是栈顶数字,直接pop出栈即可;如果希望pop的数字目前不在栈顶,我们就到push序列中还没有被push到栈里的数字中去搜索这个数字,并将在它之前的所有数字都push进栈。如果所有的数字都被push进栈仍然没有找到这个数字,表明该序列不可能是1个pop序列。

基于前面的分析,我们可以写出如下的参考代码:

#include <stack>

/

// Given a push order of a stack, determine whether an array is possible to

// be its corresponding pop order

// Input: pPush   - an array of integers, the push order

//        pPop    - an array of integers, the pop order

//        nLength - the length of pPush and pPop

// Output: If pPop is possible to be the pop order of pPush, return true、

//         Otherwise return false

/

bool IsPossiblePopOrder(const int* pPush, const int* pPop, int nLength)

{

bool bPossible = false;

if(pPush && pPop && nLength > 0)

{

const int *pNextPush = pPush;

const int *pNextPop = pPop;

// ancillary stack

std::stack<int>stackData;

// check every integers in pPop

while(pNextPop - pPop < nLength)

{

// while the top of the ancillary stack is not the integer

// to be poped, try to push some integers into the stack

while(stackData、empty() || stackData、top() != *pNextPop)

{

// pNextPush == NULL means all integers have been

// pushed into the stack, can't push any longer

if(!pNextPush)

break;

stackData、push(*pNextPush);

// if there are integers left in pPush, move

// pNextPush forward, otherwise set it to be NULL

if(pNextPush - pPush < nLength - 1)

pNextPush ++;

else

pNextPush = NULL;

}

// After pushing, the top of stack is still not same as

// pPextPop, pPextPop is not in a pop sequence

// corresponding to pPush

if(stackData、top() != *pNextPop)

break;

// Check the next integer in pPop

stackData、pop();

pNextPop ++;

}

// if all integers in pPop have been check successfully,

// pPop is a pop sequence corresponding to pPush

if(stackData、empty() && pNextPop - pPop == nLength)

bPossible = true;

}

return bPossible;

}

(25) 在从1到n的正数中1出现的次数

题目:输入1个整数n,求从1到n这n个整数的十进制表示中1出现的次数。

示例输入12,从1到12这些整数中包含1 的数字有1,10,11和12,11共出现了5次。

分析:这是1道广为流传的google面试题。用最直观的方法求解并不是很难,但遗憾的是效率不是很高;而要得出1个效率较高的算法,需要比较强的分析能力,并不是件很容易的事情。当然,google的面试题中简单的也没有几道。

首先我们来看最直观的方法,分别求得1到n中每个整数中1出现的次数。而求1个整数的十进制表示中1出现的次数,就和本面试题系列的第22题很相像了。我们每次判断整数的个位数字是不是1。如果这个数字大于10,除以10之后再判断个位数字是不是1。基于这个思路,不难写出如下的代码:

int NumberOf1(unsigned int n);

/

// Find the number of 1 in the integers between 1 and n

// Input: n - an integer

// Output: the number of 1 in the integers between 1 and n

/

int NumberOf1BeforeBetween1AndN_Solution1(unsigned int n)

{

int number = 0;

// Find the number of 1 in each integer between 1 and n

for(unsigned int i = 1; i <= n; ++ i)

number += NumberOf1(i);

return number;

}

/

// Find the number of 1 in an integer with radix 10

// Input: n - an integer

// Output: the number of 1 in n with radix

/

int NumberOf1(unsigned int n)

{

int number = 0;

while(n)

{

if(n % 10 == 1)

number ++;

n = n / 10;

}

return number;

}

这个思路有1个非常明显的缺点就是每个数字都要计算1在该数字中出现的次数,因此时间复杂度是O(n)。当输入的n非常大的时候,需要大量的计算,运算效率很低。我们试着找出1些规律,来避免不必要的计算。

我们用1个稍微大1点的数字21345作为例子来分析。我们将从1到21345的所有数字分成两段,即1-1235和1346-21345。

先来看1346-21345中1出现的次数。1的出现分为两种情况:1种情况是1出现在最高位(万位)。从1到21345的数字中,1出现在10000-19999这10000个数字的万位中,1共出现了10000(104)次;另外1种情况是1出现在除了最高位之外的其他位中。例子中1346-21345,这20000个数字中后面四位中1出现的次数是2000次(2*103,其中2的第1位的数值,103是因为数字的后四位数字其中1位为1,其余的三位数字可以在0到9这10个数字任意选择,由排列组合可以得出总次数是2*103)。

至于从1到1345的所有数字中1出现的次数,我们就可以用递归地求得了。这也是我们为什么要将1-21345分为1-1235和1346-21345两段的原因。因为将21345的最高位去掉就得到1345,便于我们采用递归的思路。

分析到这里还有1种特殊情况需要注意:前面我们举例子是最高位是1个比1大的数字,此时最高位1出现的次数104(对五位数而言)。但如果最高位是1呢?比如输入12345,从10000到12345这些数字中,1在万位出现的次数就不是104次,而是2346次了,也就是除去最高位数字之后剩下的数字再加上1。

基于前面的分析,我们可以写出以下的代码。在参考代码中,为了编程方便,我将数字转换成string了。

#include "string、h"

#include "stdlib、h"

int NumberOf1(const char* strN);

int PowerBase10(unsigned int n);

/

// Find the number of 1 in an integer with radix 10

// Input: n - an integer

// Output: the number of 1 in n with radix

/

int NumberOf1BeforeBetween1AndN_Solution2(int n)

{

if(n <= 0)

return 0;

// convert the integer into a string

char strN[50];

sprintf(strN, "%d", n);

return NumberOf1(strN);

}

/

// Find the number of 1 in an integer with radix 10

// Input: strN - a string, which represents an integer

// Output: the number of 1 in n with radix

/

int NumberOf1(const char* strN)

{

if(!strN || *strN < '0' || *strN > '9' || *strN == '\0')

return 0;

int firstDigit = *strN - '0';

unsigned int length = static_cast<unsigned int>(strlen(strN));

// the integer contains only one digit

if(length == 1 && firstDigit == 0)

return 0;

if(length == 1 && firstDigit > 0)

return 1;

// suppose the integer is 21345

// numFirstDigit is the number of 1 of 10000-19999 due to the first digit

int numFirstDigit = 0;

// numOtherDigits is the number of 1 01346-21345 due to all digits

// except the first one

int numOtherDigits = firstDigit * (length - 1) * PowerBase10(length - 2);

// numRecursive is the number of 1 of integer 1345

int numRecursive = NumberOf1(strN + 1);

// if the first digit is greater than 1, suppose in integer 21345

// number of 1 due to the first digit is 10^4、 It's 10000-19999

if(firstDigit > 1)

numFirstDigit = PowerBase10(length - 1);

// if the first digit equals to 1, suppose in integer 12345

// number of 1 due to the first digit is 2346、 It's 10000-12345

else if(firstDigit == 1)

numFirstDigit = atoi(strN + 1) + 1;

return numFirstDigit + numOtherDigits + numRecursive;

}

/

// Calculate 10^n

/

int PowerBase10(unsigned int n)

{

int result = 1;

for(unsigned int i = 0; i < n; ++ i)

result *= 10;

return result;

}

(26) 和为n连续正数序列

题目:输入1个正数n,输出所有和为n连续正数序列。

示例输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。

分析:这是网易的1道面试题。

这道题和本面试题系列的第10题有些类似。我们用两个数small和big分别表示序列的最小值和最大值。首先将small初始化为1,big初始化为2。如果从small到big的序列的和大于n的话,我们向右移动small,相当于从序列中去掉较小的数字。如果从small到big的序列的和小于n的话,我们向右移动big,相当于向序列中添加big的下1个数字。1直到small等于(1+n)/2,因为序列至少要有两个数字。

基于这个思路,我们可以写出如下代码:

void PrintContinuousSequence(int small, int big);

/

// Find continuous sequence, whose sum is n

/

void FindContinuousSequence(int n)

{

if(n < 3)

return;

int small = 1;

int big = 2;

int middle = (1 + n) / 2;

int sum = small + big;

while(small < middle)

{

// we are lucky and find the sequence

if(sum == n)

PrintContinuousSequence(small, big);

// if the current sum is greater than n,

// move small forward

while(sum > n)

{

sum -= small;

small ++;

// we are lucky and find the sequence

if(sum == n)

PrintContinuousSequence(small, big);

}

// move big forward

big ++;

sum += big;

}

}

/

// Print continuous sequence between small and big

/

void PrintContinuousSequence(int small, int big)

{

for(int i = small; i <= big; ++ i)

printf("%d ", i);

printf("\n");

}

(27) 二元树的深度

题目:输入1棵二元树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的1条路径,最长路径的长度为树的深度。

示例:输入二元树:

10

/     \

6        14

/         /   \

4         12     16

输出该树的深度3。

二元树的结点定义如下:

struct SBinaryTreeNode // a node of the binary tree

{

int               m_nValue; // value of node

SBinaryTreeNode  *m_pLeft;  // left child of node

SBinaryTreeNode  *m_pRight; // right child of node

};

分析:这道题本质上还是考查二元树的遍历。

题目给出了1种树的深度的定义。当然,我们可以按照这种定义去得到树的所有路径,也就能得到最长路径以及它的长度。只是这种思路用来写程序有点麻烦。

我们还可以从另外1个角度来理解树的深度。如果1棵树只有1个结点,它的深度为1。如果根结点只有左子树而没有右子树,那么树的深度应该是其左子树的深度加1;同样如果根结点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1。如果既有右子树又有左子树呢?那该树的深度就是其左、右子树深度的较大值再加1。

上面的这个思路用递归的方法很容易实现,只需要对遍历的代码稍作修改即可。参考代码如下:

///

// Get depth of a binary tree

// Input: pTreeNode - the head of a binary tree

// Output: the depth of a binary tree

///

int TreeDepth(SBinaryTreeNode *pTreeNode)

{

// the depth of a empty tree is 0

if(!pTreeNode)

return 0;

// the depth of left sub-tree

int nLeft = TreeDepth(pTreeNode->m_pLeft);

// the depth of right sub-tree

int nRight = TreeDepth(pTreeNode->m_pRight);

// depth is the binary tree

return (nLeft > nRight) ? (nLeft + 1) : (nRight + 1);

}

(28) string的排列

题目:输入1个string,打印出该string中字符的所有排列。示例输入stringabc,则输出由字符a、b、c所能排列出来的所有stringabc、acb、bac、bca、cab和cba。

分析:这是1道很好的考查对递归理解的编程题,因此在过去1年中频繁出现在各大公司的面试、笔试题中。

我们以三个字符abc为例来分析1下求string排列的过程。首先我们固定第1个字符a,求后面两个字符bc的排列。当两个字符bc的排列求好之后,我们将第1个字符a和后面的b交换,得到bac,接着我们固定第1个字符b,求后面两个字符ac的排列。现在是将c放到第1位置的时候了。记住前面我们已经将原先的第1个字符a和后面的b做了交换,为了保证这次c仍然是和原先处在第1位置的a交换,我们在拿c和第1个字符交换之前,先要将b和a交换回来。在交换b和a之后,再拿c和处在第1位置的a进行交换,得到cba。我们再次固定第1个字符c,求后面两个字符b、a的排列。

既然我们已经知道怎么求三个字符的排列,那么固定第1个字符之后求后面两个字符的排列,就是典型的递归思路了。

基于前面的分析,我们可以得到如下的参考代码:

void Permutation(char* pStr, char* pBegin);

/

// Get the permutation of a string,

// for example, input string abc, its permutation is

// abc acb bac bca cba cab

/

void Permutation(char* pStr)

{

Permutation(pStr, pStr);

}

/

// Print the permutation of a string,

// Input: pStr   - input string

//        pBegin - points to the begin char of string

//                 which we want to permutate in this recursion

/

void Permutation(char* pStr, char* pBegin)

{

if(!pStr || !pBegin)

return;

// if pBegin points to the end of string,

// this round of permutation is finished,

// print the permuted string

if(*pBegin == '\0')

{

printf("%s\n", pStr);

}

// otherwise, permute string

else

{

for(char* pCh = pBegin; *pCh != '\0'; ++ pCh)

{

// swap pCh and pBegin

char temp = *pCh;

*pCh = *pBegin;

*pBegin = temp;

Permutation(pStr, pBegin + 1);

// restore pCh and pBegin

temp = *pCh;

*pCh = *pBegin;

*pBegin = temp;

}

}

}

扩展1:如果不是求字符的所有排列,而是求字符的所有组合,应该怎么办呢?当输入的string中含有相同的string时,相同的字符交换位置是不同的排列,但是同1个组合。举个例子,如果输入aaa,那么它的排列是6个aaa,但对应的组合只有1个。

扩展2:输入1个含有8个数字的数组,判断有没有可能将这8个数字分别放到正方体的8个顶点上,使得正方体上三组相对的面上的4个顶点的和相等。

(29) 调整数组顺序使奇数位于偶数前面

题目:输入1个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。

分析:如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到1个偶数时,拿出这个数字,并将位于这个数字后面的所有数字往前挪动1位。挪完之后在数组的末尾有1个空位,这时将该偶数放入这个空位。由于碰到1个偶数,需要移动O(n)个数字,因此总的时间复杂度是O(n2)。

要求的是将奇数放在数组的前半部分,偶数放在数组的后半部分,因此所有的奇数应该位于偶数的前面。也就是说我们在扫描这个数组的时候,如果发现有偶数出现在奇数的前面,我们可以交换他们的顺序,交换之后就符合要求了。

因此我们可以维护两个指针,第1个指针初始化为数组的第1个数字,它只向后移动;第2个指针初始化为数组的最后1个数字,它只向前移动。在两个指针相遇之前,第1个指针总是位于第2个指针的前面。如果第1个指针指向的数字是偶数而第2个指针指向的数字是奇数,我们就交换这两个数字。

基于这个思路,我们可以写出如下的代码:

void Reorder(int *pData, unsigned int length, bool (*func)(int));

bool isEven(int n);

/

// Devide an array of integers into two parts, odd in the first part,

// and even in the second part

// Input: pData  - an array of integers

//        length - the length of array

/

void ReorderOddEven(int *pData, unsigned int length)

{

if(pData == NULL || length == 0)

return;

Reorder(pData, length, isEven);

}

/

// Devide an array of integers into two parts, the intergers which

// satisfy func in the first part, otherwise in the second part

// Input: pData  - an array of integers

//        length - the length of array

//        func   - a function

/

void Reorder(int *pData, unsigned int length, bool (*func)(int))

{

if(pData == NULL || length == 0)

return;

int *pBegin = pData;

int *pEnd = pData + length - 1;

while(pBegin < pEnd)

{

// if *pBegin does not satisfy func, move forward

if(!func(*pBegin))

{

pBegin ++;

continue;

}

// if *pEnd does not satisfy func, move backward

if(func(*pEnd))

{

pEnd --;

continue;

}

// if *pBegin satisfy func while *pEnd does not,

// swap these integers

int temp = *pBegin;

*pBegin = *pEnd;

*pEnd = temp;

}

}

/

// Determine whether an integer is even or not

// Input: an integer

// otherwise return false

/

bool isEven(int n)

{

return (n & 1) == 0;

}

讨论:

上面的代码有三点值得提出来和大家讨论:

1.函数isEven判断1个数字是不是偶数并没有用%运算符而是用&。理由是通常情况下位运算符比%要快1些;

2.这道题有很多变种。这里要求是将奇数放在偶数的前面,如果将要求改成:将负数放在非负数的前面等,思路都是都1样的。

3.在函数Reorder中,用函数指针func指向的函数来判断1个数字是不是符合给定的条件,而不是用在代码直接判断(hard code)。这样的好处是将调整顺序的算法和调整的标准分开了(即解耦,decouple)。当调整的标准改变时,Reorder的代码不需要修改,只需要提供1个新的确定调整标准的函数即可,提高了代码的可维护性。示例要求将负数放在非负数的前面,我们不需要修改Reorder的代码,只需添加1个函数来判断整数是不是非负数。这样的思路在很多库中都有广泛的应用,比如在STL的很多算法函数中都有1个仿函数(functor)的参数(当然仿函数不是函数指针,但其思想是1样的)。如果在面试中能够想到这1层,无疑能给面试官留下很好的印象。

(30) 异常安全的赋值运算符重载函数

题目:类CMyString的声明如下:

class CMyString

{

public:

CMyString(char* pData = NULL);

CMyString(const CMyString& str);

~CMyString(void);

CMyString& operator = (const CMyString& str);

private:

char* m_pData;

};

请实现其赋值运算符的重载函数,要求异常安全,即当对1个对象进行赋值时发生异常,对象的状态不能改变。

分析:首先我们来看1般C++教科书上给出的赋值运算符的重载函数:

CMyString& CMyString::operator =(const CMyString &str)

{

if(this == &str)

return *this;

delete []m_pData;

m_pData = NULL;

m_pData = new char[strlen(str、m_pData) + 1];

strcpy(m_pData, str、m_pData);

return *this;

}

我们知道,在分配内存时有可能发生异常。当执行语句new char[strlen(str、m_pData) + 1]发生异常时,程序将从该赋值运算符的重载函数退出不再执行。注意到这个时候语句delete []m_pData已经执行了。也就是说赋值操作没有完成,但原来对象的状态已经改变。也就是说不满足题目的异常安全的要求。

为了满足异常安全这个要求,1个简单的办法是掉换new、delete的顺序。先将内存new出来用1个临时指针保存起来,只有这个语句正常执行完成之后再执行delete。这样就能够保证异常安全了。

下面给出的是1个更加优雅的实现方案:

CMyString& CMyString::operator =(const CMyString &str)

{

if(this != &str)

{

CMyString strTemp(str);

char* pTemp = strTemp、m_pData;

strTemp、m_pData = m_pData;

m_pData = pTemp;

}

return *this;

}

该方案通过调用构造拷贝函数创建1个临时对象来分配内存。此时即使发生异常,对原来对象的状态没有影响。交换临时对象和需要赋值的对象的string指针之后,由于临时对象的生命周期结束,自动调用其析构函数释放需赋值对象的原来的string空间。整个函数不需要显式用到new、delete,内存的分配和释放都自动完成,因此代码显得比较优雅。

(31) 从尾到头输出链表

题目:输入1个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:

struct ListNode

{

int       m_nKey;

ListNode* m_pNext;

};

分析:这是1道很有意思的面试题。该题以及它的变体经常出现在各大公司的面试、笔试题中。

看到这道题后,第1反应是从头到尾输出比较简单。于是很自然地想到将链表中链接结点的指针反转过来,改变链表的方向。然后就可以从头到尾输出了。反转链表的算法详见本人面试题精选系列的第19题,在此不再细述。但该方法需要额外的操作,应该还有更好的方法。

接下来的想法是从头到尾遍历链表,每经过1个结点的时候,将该结点放到1个栈中。当遍历完整个链表后,再从栈顶开始输出结点的值,此时输出的结点的顺序已经反转过来了。该方法需要维护1个额外的栈,实现起来比较麻烦。

既然想到了栈来实现这个函数,而递归本质上就是1个栈结构。于是很自然的又想到了用递归来实现。要实现反过来输出链表,我们每访问到1个结点的时候,先递归输出它后面的结点,再输出该结点自身,这样链表的输出结果就反过来了。

基于这样的思路,不难写出如下代码:

///

// Print a list from end to beginning

// Input: pListHead - the head of list

///

void PrintListReversely(ListNode* pListHead)

{

if(pListHead != NULL)

{

// Print the next node first

if (pListHead->m_pNext != NULL)

{

PrintListReversely(pListHead->m_pNext);

}

// Print this node

printf("%d", pListHead->m_nKey);

}

}

扩展:该题还有两个常见的变体:

1、       从尾到头输出1个string;

2、       定义1个函数求string的长度,要求该函数体内不能声明任何变量。

(32) 不能被继承的类

题目:用C++设计1个不能被继承的类。

分析:这是Adobe公司2007年校园招聘的最新笔试题。这道题除了考察应聘者的C++基本功底外,还能考察反应能力,是1道很好的题目。

在Java中定义了关键字final,被final修饰的类不能被继承。但在C++中没有final这个关键字,要实现这个要求还是需要花费1些精力。

首先想到的是在C++ 中,子类的构造函数会自动调用父类的构造函数。同样,子类的析构函数也会自动调用父类的析构函数。要想1个类不能被继承,我们只要将它的构造函数和析构函数都定义为私有函数。那么当1个类试图从它那继承的时候,必然会由于试图调用构造函数、析构函数而导致编译错误。

可是这个类的构造函数和析构函数都是私有函数了,我们怎样才能得到该类的实例呢?这难不倒我们,我们可以通过定义静态来创建和释放类的实例。基于这个思路,我们可以写出如下的代码:

///

// Define a class which can't be derived from

///

class FinalClass1

{

public:

static FinalClass1* GetInstance()

{

return new FinalClass1;

}

static void DeleteInstance( FinalClass1* pInstance)

{

delete pInstance;

pInstance = 0;

}

private:

FinalClass1() {}

~FinalClass1() {}

};

这个类是不能被继承,但在总觉得它和1般的类有些不1样,使用起来也有点不方便。比如,我们只能得到位于堆上的实例,而得不到位于栈上实例。

能不能实现1个和1般类除了不能被继承之外其他用法都1样的类呢?办法总是有的,不过需要1些技巧。请看如下代码:

///

// Define a class which can't be derived from

///

template <typename T> class MakeFinal

{

friend T;

private:

MakeFinal() {}

~MakeFinal() {}

};

class FinalClass2 : virtual public MakeFinal<FinalClass2>

{

public:

FinalClass2() {}

~FinalClass2() {}

};

这个类使用起来和1般的类没有区别,可以在栈上、也可以在堆上创建实例。尽管类MakeFinal<FinalClass2>的构造函数和析构函数都是私有的,但由于类FinalClass2是它的友元函数,因此在FinalClass2中调用MakeFinal<FinalClass2>的构造函数和析构函数都不会造成编译错误。

但当我们试图从FinalClass2继承1个类并创建它的实例时,却不同通过编译。

class Try : public FinalClass2

{

public:

Try() {}

~Try() {}

};

Try temp;

由于类FinalClass2是从类MakeFinal<FinalClass2>虚继承过来的,在调用Try的构造函数的时候,会直接跳过FinalClass2而直接调用MakeFinal<FinalClass2>的构造函数。非常遗憾的是,Try不是MakeFinal<FinalClass2>的友元,因此不能调用其私有的构造函数。

基于上面的分析,试图从FinalClass2继承的类,1旦实例化,都会导致编译错误,因此是FinalClass2不能被继承。这就满足了我们设计要求。

(33) 在O(1)时间删除链表结点

题目:给定链表的头指针和1个结点指针,在O(1)时间删除该结点。链表结点的定义如下:

struct ListNode

{

int        m_nKey;

ListNode*  m_pNext;

};

函数的声明如下:

void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);

分析:这是1道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,更重要的是,还能考察我们对时间复杂度的理解。

在链表中删除1个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然就是O(n) 了。

我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面1个结点。我们试着换1种思路。我们可以从给定的结点得到它的下1个结点。这个时候我们实际删除的是它的下1个结点,由于我们已经得到实际删除的结点的前面1个结点,因此完全是可以实现的。当然,在删除之前,我们需要需要将给定的结点的下1个结点的数据拷贝到给定的结点中。此时,时间复杂度为O(1)。

上面的思路还有1个问题:如果删除的结点位于链表的尾部,没有下1个结点,怎么办?我们仍然从链表的头结点开始,顺便遍历得到给定结点的前序结点,并完成删除操作。这个时候时间复杂度是O(n)。

那题目要求我们需要在O(1)时间完成删除操作,我们的算法是不是不符合要求?实际上,假设链表总共有n个结点,我们的算法在n-1总情况下时间复杂度是O(1),只有当给定的结点处于链表末尾的时候,时间复杂度为O(n)。那么平均时间复杂度[(n-1)*O(1)+O(n)]/n,仍然为O(1)。

基于前面的分析,我们不难写出下面的代码。

参考代码:

///

// Delete a node in a list

// Input: pListHead - the head of list

//        pToBeDeleted - the node to be deleted

///

void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted)

{

if(!pListHead || !pToBeDeleted)

return;

// if pToBeDeleted is not the last node in the list

if(pToBeDeleted->m_pNext != NULL)

{

// copy data from the node next to pToBeDeleted

ListNode* pNext = pToBeDeleted->m_pNext;

pToBeDeleted->m_nKey = pNext->m_nKey;

pToBeDeleted->m_pNext = pNext->m_pNext;

// delete the node next to the pToBeDeleted

delete pNext;

pNext = NULL;

}

// if pToBeDeleted is the last node in the list

else

{

// get the node prior to pToBeDeleted

ListNode* pNode = pListHead;

while(pNode->m_pNext != pToBeDeleted)

{

pNode = pNode->m_pNext;

}

// deleted pToBeDeleted

pNode->m_pNext = NULL;

delete pToBeDeleted;

pToBeDeleted = NULL;

}

}

值得注意的是,为了让代码看起来简洁1些,上面的代码基于两个假设:(1)给定的结点的确在链表中;(2)给定的要删除的结点不是链表的头结点。不考虑第1个假设对代码的鲁棒性是有影响的。至于第2个假设,当整个列表只有1个结点时,代码会有问题。但这个假设不算很过分,因为在有些链表的实现中,会创建1个虚拟的链表头,并不是1个实际的链表结点。这样要删除的结点就不可能是链表的头结点了。当然,在面试中,我们可以将这些假设和面试官交流。这样,面试官还是会觉得我们考虑问题很周到的。

(34) 找出数组中两个只出现1次的数字

题目:1个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现1次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

分析:这是1道很新颖的关于位运算的面试题。

首先我们考虑这个问题的1个简单版本:1个数组里除了1个数字之外,其他的数字都出现了两次。请写程序找出这个只出现1次的数字。

这个题目的突破口在哪里?题目为什么要强调有1个数字出现1次,其他的出现两次?我们想到了异或运算的性质:任何1个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每1个数字,那么最终的结果刚好是那个只出现依次的数字,因为那些出现两次的数字全部在异或中抵消掉了。

有了上面简单问题的解决方案之后,我们回到原始的问题。如果能够将原数组分为两个子数组。在每个子数组中,包含1个只出现1次的数字,而其他数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现1次的数字了。

我们还是从头到尾依次异或数组中的每1个数字,那么最终得到的结果就是两个只出现1次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了。由于这两个数字肯定不1样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有1位为1。我们在结果数字中找到第1个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准将原数组中的数字分成两个子数组,第1个子数组中每个数字的第N位都为1,而第2个子数组的每个数字的第N位都为0。

现在我们已经将原数组分成了两个子数组,每个子数组都包含1个只出现1次的数字,而其他数字都出现了两次。因此到此为止,所有的问题我们都已经解决。

基于上述思路,我们不难写出如下代码:

///

// Find two numbers which only appear once in an array

// Input: data - an array contains two number appearing exactly once,

//               while others appearing exactly twice

//        length - the length of data

// Output: num1 - the first number appearing once in data

//         num2 - the second number appearing once in data

///

void FindNumsAppearOnce(int data[], int length, int &num1, int &num2)

{

if (length < 2)

return;

// get num1 ^ num2

int resultExclusiveOR = 0;

for (int i = 0; i < length; ++ i)

resultExclusiveOR ^= data[i];

// get index of the first bit, which is 1 in resultExclusiveOR

unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);

num1 = num2 = 0;

for (int j = 0; j < length; ++ j)

{

// divide the numbers in data into two groups,

// the indexOf1 bit of numbers in the first group is 1,

// while in the second group is 0

if(IsBit1(data[j], indexOf1))

num1 ^= data[j];

else

num2 ^= data[j];

}

}

///

// Find the index of first bit which is 1 in num (assuming not 0)

///

unsigned int FindFirstBitIs1(int num)

{

int indexBit = 0;

while (((num & 1) == 0) && (indexBit < 32))

{

num = num >> 1;

++ indexBit;

}

return indexBit;

}

///

// Is the indexBit bit of num 1?

///

bool IsBit1(int num, unsigned int indexBit)

{

num = num >> indexBit;

return (num & 1);

}

(35) 找出两个链表的第1个公共结点

题目:两个单向链表,找出它们的第1个公共结点。

链表的结点定义为:

struct ListNode

{

int       m_nKey;

ListNode*   m_pNext;

};

分析:这是1道微软的面试题。微软非常喜欢与链表相关的题目,因此在微软的面试题中,链表出现的概率相当高。

如果两个单向链表有公共的结点,也就是说两个链表从某1结点开始,它们的m_pNext都指向同1个结点。但由于是单向链表的结点,每个结点只有1个m_pNext,因此从第1个公共结点开始,之后它们所有结点都是重合的,不可能再出现分叉。所以,两个有公共结点而部分重合的链表,拓扑形状看起来像1个Y,而不可能像X。

看到这个题目,第1反应就是蛮力法:在第1链表上顺序遍历每个结点。每遍历1个结点的时候,在第2个链表上顺序遍历每个结点。如果此时两个链表上的结点是1样的,说明此时两个链表重合,于是找到了它们的公共结点。如果第1个链表的长度为m,第2个链表的长度为n,显然,该方法的时间复杂度为O(mn)。

接下来我们试着去寻找1个线性时间复杂度的算法。我们先将问题简化:如何判断两个单向链表有没有公共结点?前面已经提到,如果两个链表有1个公共结点,那么该公共结点之后的所有结点都是重合的。那么,它们的最后1个结点必然是重合的。因此,我们判断两个链表是不是有重合的部分,只要分别遍历两个链表到最后1个结点。如果两个尾结点是1样的,说明它们用重合;否则两个链表没有公共的结点。

在上面的思路中,顺序遍历两个链表到尾结点的时候,我们不能保证在两个链表上同时到达尾结点。这是因为两个链表不1定长度1样。但如果假设1个链表比另1个长l个结点,我们先在长的链表上遍历l个结点,之后再同步遍历,这个时候我们就能保证同时到达最后1个结点了。由于两个链表从第1个公共结点考试到链表的尾结点,这1部分是重合的。因此,它们肯定也是同时到达第1公共结点的。于是在遍历中,第1个相同的结点就是第1个公共的结点。

在这个思路中,我们先要分别遍历两个链表得到它们的长度,并求出两个长度之差。在长的链表上先遍历若干次之后,再同步遍历两个链表,知道找到相同的结点,或者1直到链表结束。此时,如果第1个链表的长度为m,第2个链表的长度为n,该方法的时间复杂度为O(m+n)。

基于这个思路,我们不难写出如下的代码:

///

// Find the first common node in the list with head pHead1 and

// the list with head pHead2

// Input: pHead1 - the head of the first list

//        pHead2 - the head of the second list

// Return: the first common node in two list、 If there is no common

//         nodes, return NULL

///

ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2)

{

// Get the length of two lists

unsigned int nLength1 = ListLength(pHead1);

unsigned int nLength2 = ListLength(pHead2);

int nLengthDif = nLength1 - nLength2;

// Get the longer list

ListNode *pListHeadLong = pHead1;

ListNode *pListHeadShort = pHead2;

if(nLength2 > nLength1)

{

pListHeadLong = pHead2;

pListHeadShort = pHead1;

nLengthDif = nLength2 - nLength1;

}

// Move on the longer list

for(int i = 0; i < nLengthDif; ++ i)

pListHeadLong = pListHeadLong->m_pNext;

// Move on both lists

while((pListHeadLong != NULL) &&

(pListHeadShort != NULL) &&

(pListHeadLong != pListHeadShort))

{

pListHeadLong = pListHeadLong->m_pNext;

pListHeadShort = pListHeadShort->m_pNext;

}

// Get the first common node in two lists

ListNode *pFisrtCommonNode = NULL;

if(pListHeadLong == pListHeadShort)

pFisrtCommonNode = pListHeadLong;

return pFisrtCommonNode;

}

///

// Get the length of list with head pHead

// Input: pHead - the head of list

// Return: the length of list

///

unsigned int ListLength(ListNode* pHead)

{

unsigned int nLength = 0;

ListNode* pNode = pHead;

while(pNode != NULL)

{

++ nLength;

pNode = pNode->m_pNext;

}

return nLength;

}

(36) 在string中删除特定的字符

题目:输入两个string,从第1string中删除第2个string中所有的字符。示例,输入”They are students、” 和”aeiou” ,则删除之后的第1个string变成”Thy r stdnts、” 。

分析:这是1道微软面试题。在微软的常见面试题中,与string相关的题目占了很大的1部分,因为写程序操作string能很好的反映我们的编程基本功。

要编程完成这道题要求的功能可能并不难。毕竟,这道题的基本思路就是在第1个string中拿到1个字符,在第2个string中查找1下,看它是不是在第2个string中。如果在的话,就从第1个string中删除。但如何能够将效率优化到让人满意的程度,却也不是1件容易的事情。也就是说,如何在第1个string中删除1个字符,以及如何在第2string中查找1个字符,都是需要1些小技巧的。

首先我们考虑如何在string中删除1个字符。由于string的内存分配方式是连续分配的。我们从string当中删除1个字符,需要将后面所有的字符往前移动1个字节的位置。但如果每次删除都需要移动string后面的字符的话,对于1个长度为n 的string而言,删除1个字符的时间复杂度为O(n) 。而对于本题而言,有可能要删除的字符的个数是n ,因此该方法就删除而言的时间复杂度为O(n2) 。

事实上,我们并不需要在每次删除1个字符的时候都去移动后面所有的字符。我们可以设想,当1个字符需要被删除的时候,我们将它所占的位置让它后面的字符来填补,也就相当于这个字符被删除了。在具体实现中,我们可以定义两个指针(pFast 和pSlow) ,初始的时候都指向第1字符的起始位置。当pFast 指向的字符是需要删除的字符,则pFast 直接跳过,指向下1个字符。如果pFast 指向的字符是不需要删除的字符,那么将pFast 指向的字符赋值给pSlow 指向的字符,并且pFast 和pStart 同时向后移动指向下1个字符。这样,前面被pFast 跳过的字符相当于被删除了。用这种方法,整个删除在O(n) 时间内就可以完成。

接下来我们考虑如何在1个string中查找1个字符。当然,最简单的办法就是从头到尾扫描整个string。显然,这种方法需要1个循环,对于1个长度为n 的string,时间复杂度是O(n) 。

由于字符的总数是有限的。对于八位的char 型字符而言,总共只有28=256 个字符。我们可以新建1个大小为256 的数组,将所有元素都初始化为0 。然后对于string中每1个字符,将它的ASCII 码映射成索引,将数组中该索引对应的元素设为1。这个时候,要查找1个字符就变得很快了:根据这个字符的ASCII 码,在数组中对应的下标找到该元素,如果为0 ,表示string中没有该字符,否则string中包含该字符。此时,查找1个字符的时间复杂度是O(1) 。其实,这个数组就是1个hash 表。这种思路的详细说明,详见 本面试题系列的第13 题 。

基于上述分析,我们可以写出如下代码:

// Delete all characters in pStrDelete from pStrSource

///

void DeleteChars(char* pStrSource, const char* pStrDelete)

{

if(NULL == pStrSource || NULL == pStrDelete)

return;

// Initialize an array, the index in this array is ASCII value、

// All entries in the array, whose index is ASCII value of a

// character in the pStrDelete, will be set as 1、

// Otherwise, they will be set as 0、

const unsigned int nTableSize = 256;

int hashTable[nTableSize];

memset(hashTable, 0, sizeof(hashTable));

const char* pTemp = pStrDelete;

while ('\0' != *pTemp)

{

hashTable[*pTemp] = 1;

++ pTemp;

}

char* pSlow = pStrSource;

char* pFast = pStrSource;

while ('\0' != *pFast)

{

// if the character is in pStrDelete, move both pStart and

// pEnd forward, and copy pEnd to pStart、

// Otherwise, move only pEnd forward, and the character

// pointed by pEnd is deleted

if(1 != hashTable[*pFast])

{

*pSlow = *pFast;

++ pSlow;

}

++pFast;

}

*pSlow = '\0';

}

5 IT公司笔试题算法部分(26道题,中等)

1、将1整数逆序后放入1数组中(要求递归实现)

void convert(int *result, int n)

{

if(n>=10)

convert(result+1, n/10);

*result = n%10;

}

int main(int argc, char* argv[])

{

int n = 123456789, result[20]={};

convert(result, n);

printf("%d:", n);

for(int i=0; i<9; i++)

printf("%d", result[i]);

return getchar();

}

2、求高于平均分的学生学号及成绩(学号和成绩人工输入)

double find(int total, int n)

{

int number, score,  average;

scanf("%d", &number);

if(number != 0){

scanf("%d", &score);

average = find(total+score, n+1);

if(score >= average)

printf("%d:%d\n", number, score);

return average;

}else{

printf("Average=%d\n", total/n);

return total/n;

}

}

int main(int argc, char* argv[])

{

find(0, 0);

return getchar();

}

3、递归实现回文判断(如:abcdedbca就是回文)

int find(char *str, int n)

{

if(n<=1) return 1;

else if(str[0]==str[n-1]) return find(str+1, n-2);

else return 0;

}

int main(int argc, char* argv[])

{

char *str = "abcdedcba";

printf("%s: %s\n", str, find(str,

strlen(str)) ? "Yes" : "No");

return getchar();

}

4、组合问题(从M个不同字符中任取N个字符的所有组合)

void find(char *source, char *result, int n)

{

if(n==1){

while(*source)

printf("%s%c\n", result, *source++);

}else{

int i, j;

for(i=0; source[i] != 0; i++);

for(j=0; result[j] != 0; j++);

for(; i>=n; i--)

{

result[j] = *source++;

result[j+1] = '\0';

find(source, result, n-1);

}

}

}

int main(int argc, char* argv[])

{

int const n = 3;

char *source = "ABCDE", result[n+1] = {0};

if(n>0 && strlen(source)>0 && n<=strlen(source))

find(source, result, 3);

return getchar();

}

5、分解成质因数(如435234=251*17*17*3*2)

void prim(int m, int n)

{

if(m>n){

while(m%n != 0) n++;

m /= n;

prim(m, n);

printf("%d*", n);

}

}

int main(int argc, char* argv[])

{

int n = 435234;

printf("%d=", n);

prim(n, 2);

return getchar();

}

6、寻找迷宫的1条出路(o:通路; X障碍)

#define MAX_SIZE  8

int H[4] = {0, 1, 0, -1};

int V[4] = {-1, 0, 1, 0};

char Maze[MAX_SIZE][MAX_SIZE] = {{'X','X','X','X','X','X','X','X'},

{'o','o','o','o','o','X','X','X'},

{'X','o','X','X','o','o','o','X'},

{'X','o','X','X','o','X','X','o'},

{'X','o','X','X','X','X','X','X'},

{'X','o','X','X','o','o','o','X'},

{'X','o','o','o','o','X','o','o'},

{'X','X','X','X','X','X','X','X'}};

void FindPath(int X, int Y)

{

if(X == MAX_SIZE || Y == MAX_SIZE){

for(int i = 0; i < MAX_SIZE; i++)

for(int j = 0; j < MAX_SIZE; j++)

printf("%c%c", Maze[i][j], j < MAX_SIZE-1 ? ' ' : '\n');

}else for(int k = 0; k < 4; k++)

if(X >= 0 && Y >= 0 && Y < MAX_SIZE && X < MAX_SIZE && 'o' == Maze[X][Y]){

Maze[X][Y] = ' ';

FindPath(X+V[k], Y+H[k]);

Maze[X][Y] ='o';

}

}

int main(int argc, char* argv[])

{

FindPath(1,0);

return getchar();

}

7、随机分配座位,共50个学生,使学号相邻的同学座位不能相邻(早些时候用C#写的,没有用C改写)。

static void Main(string[] args)

{

int Tmp = 0, Count = 50;

int[] Seats = new int[Count];

bool[] Students = new bool[Count];

System、Random RandStudent=new System、Random();

Students[Seats[0]=RandStudent、Next(0,Count)]=true;

for(int i = 1; i < Count; )

{

Tmp=(int)RandStudent、Next(0,Count);

if((!Students[Tmp])&&(Seats[i-1]-Tmp!=1) && (Seats[i-1] - Tmp) != -1){

Seats[i++] = Tmp;

Students[Tmp] = true;

}

}

foreach(int Student in Seats)

System、Console、Write(Student + " ");

System、Console、Read();

}

8、求网格中的黑点分布(有6*7的网格,在某些格子中有黑点,已知各行与各列中有黑点的点数之和)

#define ROWS 6

#define COLS 7

int iPointsR[ROWS] = {2, 0, 4, 3, 4, 0};           // 各行黑点数和的情况

int iPointsC[COLS] = {4, 1, 2, 2, 1, 2, 1};        // 各列黑点数和的情况

int iCount, iFound;

int iSumR[ROWS], iSumC[COLS], Grid[ROWS][COLS];

int Set(int iRowNo)

{

if(iRowNo == ROWS){

for(int iColNo=0; iColNo < COLS && iSumC[iColNo]==iPointsC[iColNo]; iColNo++)

if(iColNo == COLS-1){

printf("\nNo、%d:\n", ++iCount);

for(int i=0; i < ROWS; i++)

for(int j=0; j < COLS; j++)

printf("%d%c", Grid[i][j], (j+1) % COLS ? ' ' : '\n');

iFound = 1;                         // iFound = 1,有解

}

}else{

for(int iColNo=0; iColNo < COLS; iColNo++)

{

if(iPointsR[iRowNo] == 0){

Set(iRowNo + 1);

}else if(Grid[iRowNo][iColNo]==0){

Grid[iRowNo][iColNo] = 1;

iSumR[iRowNo]++; iSumC[iColNo]++;                                  if(iSumR[iRowNo]<iPointsR[iRowNo] && iSumC[iColNo]<=iPointsC[iColNo])

Set(iRowNo);

else if(iSumR[iRowNo]==iPointsR[iRowNo] && iRowNo < ROWS)

Set(iRowNo + 1);

Grid[iRowNo][iColNo] = 0;

iSumR[iRowNo]--; iSumC[iColNo]--;

}

}

}

return iFound;   // 用于判断是否有解

}

int main(int argc, char* argv[])

{

if(!Set(0))

printf("Failure!");

return getchar();

}

9、有4种面值(面值为1, 4, 12, 21)的邮票很多枚,从中最多任取5张进行组合,求邮票最大连续组合值

#define N 5

#define M 5

int k, Found, Flag[N];

int Stamp[M] = {0, 1, 4, 12, 21};

// 在剩余张数n中组合出面值和Value

int Combine(int n, int Value)

{

if(n >= 0 && Value == 0){

Found = 1;

int Sum = 0;

for(int i=0; i<N && Flag[i] != 0; i++){

Sum += Stamp[Flag[i]];

printf("%d ", Stamp[Flag[i]]);

}

printf("\tSum=%d\n\n", Sum);

}else for(int i=1; i<M && !Found && n>0; i++)

if(Value-Stamp[i] >= 0){

Flag[k++] = i;

Combine(n-1, Value-Stamp[i]);

Flag[--k] = 0;

}

return Found;

}

int main(int argc, char* argv[])

{

for(int i=1; Combine(N, i); i++, Found=0);

return getchar();

}

10、大整数数相乘的问题。

void Multiple(char A[], char B[], char C[])

{

int TMP, In=0, LenA=-1, LenB=-1;

while(A[++LenA] != '\0');

while(B[++LenB] != '\0');

int Index, Start = LenA + LenB - 1;

for(int i=LenB-1; i>=0; i--)

{

Index = Start--;

if(B[i] != '0'){

for(int In=0, j=LenA-1; j>=0; j--)

{

TMP = (C[Index]-'0') + (A[j]-'0') * (B[i] - '0') + In;

C[Index--] = TMP % 10 + '0';

In = TMP / 10;

}

C[Index] = In + '0';

}

}

}

int main(int argc, char* argv[])

{

char A[] = "21839244444444448880088888889";

char B[] = "38888888888899999999999999988";

char C[sizeof(A) + sizeof(B) - 1];

for(int k=0; k<sizeof(C); k++)

C[k] = '0';

C[sizeof(C) 1] = '\0';

Multiple(A, B, C);

for(int i=0; C[i] != '\0'; i++)

printf("%c", C[i]);

return getchar();

}

11、求最大连续递增数字串(如“ads3sl456789DF3456ld345AA”中的“456789”)

int GetSubString(char *strSource, char *strResult)

{

int iTmp=0, iHead=0, iMax=0;

for(int Index=0, iLen=0; strSource[Index]; Index++)

{

if(strSource[Index] >= '0' && strSource[Index] <= '9'

&& strSource[Index-1] > '0' && strSource[Index] == strSource[Index-1]+1)

{

iLen++;                     // 连续数字的长度增1

}else

{                          // 出现字符或不连续数字

if(iLen > iMax)

{

iMax = iLen;

iHead = iTmp;

}

// 该字符是数字,但数字不连续

if(strSource[Index] >= '0' && strSource[Index] <= '9'){

iTmp = Index;

iLen = 1;

}

}

}

for(iTmp=0 ; iTmp < iMax; iTmp++) // 将原string中最长的连续数字串赋值给结果串

strResult[iTmp] = strSource[iHead++];

strResult[iTmp]='\0';

return iMax; // 返回连续数字的最大长度

}

int main(int argc, char* argv[])

{

char strSource[]="ads3sl456789DF3456ld345AA", char strResult[sizeof(strSource)];

printf("Len=%d, strResult=%s \nstrSource=%s\n", GetSubString(strSource, strResult),

strResult, strSource);

return getchar();

}

12、四个工人,四个任务,每个人做不同的任务需要的时间不同,求任务分配的最优方案。(2005年5月29日全国计算机软件资格水平考试——软件设计师的算法题)。

#include "stdafx、h"

#define N 4

int Cost[N][N] = { {2, 12, 5, 32}, // 行号:任务序号,列号:工人序号

{8, 15, 7, 11}, // 每行元素值表示这个任务由不同工人完成所需要的时间

{24, 18, 9, 6},

{21, 1, 8, 28}};

int MinCost=1000;

int Task[N], TempTask[N], Worker[N];

void Assign(int k, int cost)

{

if(k==N)

{

MinCost = cost;

for(int i=0; i<N; i++)

TempTask[i] = Task[i];

}else{

for(int i=0; i<N; i++){

if(Worker[i]==0 && cost+Cost[k][i] < MinCost)

{

Worker[i] = 1; Task[k] = i;

Assign(k+1, cost+Cost[k][i]);

Worker[i] = 0; Task[k] = 0;

}

}

}

}

int main(int argc, char* argv[])

{

Assign(0, 0);

printf("最佳方案总费用=%d\n", MinCost);

for(int i=0; i<N; i++) /* 输出最佳方案 */

printf("\t任务%d由工人%d来做:%d\n", i, TempTask[i], Cost[i][TempTask[i]]);

return getchar();

}

13、八皇后问题(输出所有情况,不过有些结果只是旋转了90度而已)。哈哈:)回溯算法的典型例题

#define N 8

int Board[N][N];

int Valid(int i, int j) // 所下棋子有效性的严正

{

int k = 1;

for(k=1; i>=k && j>=k;k++)

if(Board[i-k][j-k]) return 0;

for(k=1; i>=k;k++)

if(Board[i-k][j]) return 0;

for(k=1; i>=k && j+k<N;k++)

if(Board[i-k][j+k]) return 0;

return 1;

}

void Trial(int i, int n)

{

if(i==n){

for(int k=0; k<n; k++){

for(int m=0; m<n; m++)

printf("%d ", Board[k][m]);

printf("\n");

}

printf("\n");

}else{

for(int j=0; j<n; j++){

Board[i][j] = 1;

if(Valid(i,j))

Trial(i+1, n);

Board[i][j] = 0;

}

}

}

int main(int argc, char* argv[])

{

Trial(0, N);

return getchar();

}

14、实现strstr功能(寻找子串在父串中首次出现的位置)

char * strstring(char *ParentString, char *SubString)

{

char *pSubString, *pPareString;

for(char *pTmp=ParentString; *pTmp; pTmp++)

{

pSubString = SubString;

pPareString = pTmp;

while(*pSubString == *pPareString && *pSubString != '\0')

{

pSubString++;

pPareString++;

}

if(*pSubString == '\0')  return pTmp;

}

return NULL;

}

int main(int argc, char* argv[])

{

char *ParentString = "happy birthday to you!";

char *SubString = "birthday";

printf("%s",strstring(ParentString, SubString));

return getchar();

}}

15、现在小明1家过1座桥,过桥的时候是黑夜,所以必须有灯。现在小明过桥要1秒,小明的弟弟要3秒,小明的爸爸要6秒,小明的妈妈要八秒,小明的爷爷要12秒。每次此桥最多可过两人,而过桥的速度依过桥最慢者而定,而且灯在点燃后30秒就会熄灭。问小明1家如何过桥?(原本是个智力题,这里用程序来求解)

#include "stdafx、h"

#define N    5

#define SIZE 64

// 将人员编号:小明-0,弟弟-1,爸爸-2,妈妈-3,爷爷-4

// 每个人的当前位置:0--在桥左边, 1--在桥右边

int Position[N];

// 过桥临时方案的数组下标; 临时方案; 最小时间方案;

int Index, TmpScheme[SIZE], Scheme[SIZE];

// 最小过桥时间总和,初始值100;每个人过桥所需要的时间

int MinTime=100, Time[N]={1, 3, 6, 8, 12};

// 寻找最佳过桥方案。Remnant:未过桥人数; CurTime:当前已用时间;

// Direction:过桥方向,1--向右,0--向左

void Find(int Remnant, int CurTime, int Direction)

{

if(Remnant==0){                               // 所有人已经过桥,更新最少时间及方案

MinTime=CurTime;

for(int i=0; i<SIZE && TmpScheme[i]>=0; i++)

{

Scheme[i]=TmpScheme[i];

}

}else if(Direction==1){                        // 过桥方向向右,从桥左侧选出两人过桥

for(int i=0; i<N; i++)

{

if(Position[i]==0 && CurTime+Time[i]<MinTime){

TmpScheme[Index++] = i;

Position[i] = 1;

for(int j=0; j<N; j++)

{

int TmpMax = (Time[i]>Time[j] ? Time[i] : Time[j]);

if(Position[j]==0 && CurTime+TmpMax<MinTime)

{

TmpScheme[Index++] = j;

Position[j] = 1;

Find(Remnant-2, CurTime+TmpMax, !Direction);

Position[j] = 0;

TmpScheme[--Index] = -1;

}

}

Position[i] = 0;

TmpScheme[--Index] = -1;

}

}

}else{        // 过桥方向向左,从桥右侧选出1个人回来送灯

for(int j=0; j<N; j++)

{

if(Position[j]==1 && CurTime+Time[j] < MinTime)

{

TmpScheme[Index++] = j;

Position[j] = 0;

Find(Remnant+1, CurTime+Time[j], !Direction);

Position[j] = 1;

TmpScheme[--Index] = -1;

}

}

}

}

int main(int argc, char* argv[])

{

for(int i=0; i<SIZE; i++)  // 初始方案内容为负值,避免和人员标号冲突

Scheme[i] = TmpScheme[i] = -1;

Find(N, 0, 1);     // 查找最佳方案

printf("MinTime=%d:", MinTime); // 输出最佳方案

for(int i=0; i<SIZE && Scheme[i]>=0; i+=3)

printf("  %d-%d  %d", Scheme[i], Scheme[i+1], Scheme[i+2]);

printf("\b\b  ");

return getchar();

}

16、2005年11月金山笔试题。编码完成下面的处理函数。函数将string中的字符'*'移到串的前部分,前面的非'*'字符后移,但不能改变非'*'字符的先后顺序,函数返回串中字符'*'的数量。如原始串为:ab**cd**e*12,处理后为*****abcde12,函数并返回值为5。(要求使用尽量少的时间和辅助空间)

int change(char *str) /* 这个算法并不高效,从后向前搜索效率要高些 */

{

int count = 0; /* 记录串中字符'*'的个数 */

for(int i=0, j=0; str[i]; i++) /* 重串首开始遍历 */

{

if(str[i]=='*'){ /* 遇到字符'*' */

for(j=i-1; str[j]!='*'&&j>=0; j--) /* 采用类似插入排序的思想,将*前面 */

str[j+1]=str[j];   /* 的非*字符逐个后移,直到遇到*字符 */

str[j+1] = '*';

count++;

}

}

return count;

}

int main(int argc, char* argv[])

{

char str[] = "ab**cd**e*12";

printf("str1=%s\n", str);

printf("str2=%s, count=%d", str, change(str));

return getchar();

}

// 终于得到1个比较高效的算法,1个网友提供,应该和金山面试官的想法1致。算法如下:

int change(char *str)

{

int i,j=strlen(str) 1;

for(i=j; j>=0; j--)

{

if(str[i]!='*'){

i--;

}else if(str[j]!='*'){

str[i] = str[j];

str[j] = '*';

i--;

}

}

return i+1;

}

17、2005年11月15日华为软件研发笔试题。实现1单链表的逆转。

#include "stdafx、h"

typedef char eleType; // 定义链表中的数据类型

typedef struct listnode // 定义单链表结构

{

eleType data;

struct listnode *next;

}node;

node *create(int n) // 创建单链表,n为节点个数

{

node *p = (node *)malloc(sizeof(node));

node *head = p;  head->data = 'A';

for(int i='B'; i<'A'+n; i++)

{

p = (p->next = (node *)malloc(sizeof(node)));

p->data = i;

p->next = NULL;

}

return head;

}

void print(node *head) // 按链表顺序输出链表中元素

{

for(; head; head = head->next)

printf("%c ", head->data);

printf("\n");

}

node *reverse(node *head, node *pre) // 逆转单链表函数。这是笔试时需要写的最主要函数

{

node *p=head->next;

head->next = pre;

if(p)

return reverse(p, head);

else

return head;

}

int main(int argc, char* argv[])

{

node *head = create(6);

print(head);

head = reverse(head, NULL);

print(head);

return getchar();

}

18、编码实现string转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。如将string ”+123”à123, ”-0123”à-123, “123CS45”à123, “123、45CS”à123, “CS123、45”à0

#include "stdafx、h"

int str2int(const char *str) // string转整型函数

{

int i=0, sign=1, value = 0;

if(str==NULL) return NULL; // 空串直接返回 NULL

if(str[0]=='-' || str[0]=='+'){ // 判断是否存在符号位

i = 1;

sign = (str[0]=='-' ? -1 : 1);

}

for(; str[i]>='0' && str[i]<='9'; i++) // 如果是数字,则继续转换

value = value * 10 + (str[i] - '0');

return sign * value;

}

int main(int argc, char *argv[])

{

char *str = "-123、45CS67";

int  val  = str2int(str);

printf("str=%s\tval=%d\n", str, val);

return getchar();

}

19、歌德巴赫猜想。任何1个偶数都可以分解为两个素数之和。

#include "stdafx、h"

#include "math、h"

int main(int argc, char* argv[])

{

int Even=78, Prime1, Prime2, Tmp1, Tmp2;

for(Prime1=3; Prime1<=Even/2; Prime1+=2)

{

for(Tmp1=2,Tmp2=sqrt(float(Prime1)); Tmp1<=Tmp2 && Prime1%Tmp1 != 0; Tmp1++);

if(Tmp1<=Tmp2) continue;

Prime2 = Even-Prime1;

for(Tmp1=2,Tmp2=sqrt(float(Prime2)); Tmp1<=Tmp2 && Prime2%Tmp1 != 0; Tmp1++);

if(Tmp1<=Tmp2) continue;

printf("%d=%d+%d\n", Even, Prime1, Prime2);

}

return getchar();

}

20、快速排序(东软喜欢考类似的算法填空题,又如堆排序的算法等)

#include "stdafx、h"

#define N 10

int part(int list[], int low, int high)   // 1趟排序,返回分割点位置

{

int tmp = list[low];

while(low<high){

while(low<high && list[high]>=tmp) --high;

list[low] = list[high];

while(low<high && list[low]<=tmp) ++low;

list[high] = list[low];

}

list[low] = tmp;

return low;

}

void QSort(int list[], int low, int high) // 应用递归进行快速排序

{

if(low<high){

int mid = part(list, low, high);

QSort(list, low, mid-1);

QSort(list, mid+1, high);

}

}

void show(int list[], int n)              // 输出列表中元素

{

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

printf("%d ", list[i]);

printf("\n");

}

int main(int argc, char* argv[])

{

int list[N] = {23, 65, 26, 1, 6, 89, 3, 12, 33, 8};

show(list, N);                       // 输出排序前序列

QSort(list, 0, N-1);                 // 快速排序

show(list, N);                       // 输出排序后序列

return getchar();

}

21、2005年11月23日慧通笔试题:写1函数判断某个整数是否为回文数,如12321为回文数。可以用判断入栈和出栈是否相同来实现(略微复杂些),这里是将整数逆序后形成另1整数,判断两个整数是否相等来实现的。

#include "stdafx、h"

int IsEchoNum(int num)

{

int m = 0;

for(int n = num; n; n/=10)

m = m*10 + n%10;

return m==num;

}

int main(int argc, char* argv[])

{

int num = 12321;

printf("%d %d\n", num, IsEchoNum(num));

return getchar();

}

22、删除string中的数字并压缩string(神州数码以前笔试题),如string”abc123de4fg56”处理后变为”abcdefg”。注意空间和效率。(下面的算法只需要1次遍历,不需要开辟新空间,时间复杂度为O(N))

#include "stdafx、h"

void delNum(char *str)

{

int i, j=0;

for(i=j=0; str[i] && (str[i]<'0' || str[i]>'9'); j=++i);// 找到串中第1个数字的位子

for(; str[i]; i++)     // 从串中第1个数字的位置开始,逐个放入后面的非数字字符

if(str[i]<'0' || str[i]>'9')

str[j++] = str[i];

str[j] = '\0';

}

int main(int argc, char* argv[])

{

char str[] = "abc123ef4g4h5";

printf("%s\n", str);

delNum(str);

printf("%s\n", str);

return getchar();

}

23、求两个串中的第1个最长子串(神州数码以前试题)。如"abractyeyt","dgdsaeactyey"的最大子串为"actyet"。

#include "stdafx、h"

char *MaxSubString(char *str1, char *str2)

{

int i, j, k, index, max=0;

for(i=0; str1[i]; i++)

for(j=0; str2[j]; j++)

{

for(k=0; str1[i+k]==str2[j+k] && (str2[i+k] || str1[i+k]); k++);

if(k>max){         // 出现大于当前子串长度的子串,则替换子串位置和程度

index = j;    max = k;

}

}

char *strResult = (char *)calloc(sizeof(char), max+1);

for(i=0; i<max; i++)

strResult[i] = str2[index++];

return strResult;

}

int main(int argc, char* argv[])

{

char str1[] = "abractyeyt", str2[] = "dgdsaeactyey";

char *strResult = MaxSubString(str1, str2);

printf("str1=%s\nstr2=%s\nMaxSubString=%s\n", str1, str2, strResult);

return getchar();

}

24、不开辟新空间完成string的逆序

#include "stdafx、h"

void change(char *str)

{

for(int i=0,j=strlen(str) 1; i<j; i++, j--)

{

str[i] ^= str[j] ^= str[i] ^= str[j];

}

}

int main(int argc, char* argv[])

{

char str[] = "abcdefg";

printf("strSource=%s\n", str);

change(str);

printf("strResult=%s\n", str);

return getchar();

}

25、删除串中指定的字符

#include "stdafx、h"

void delChar(char *str, char c)

{

int i, j=0;

for(i=0; str[i]; i++)

if(str[i]!=c) str[j++]=str[i];

str[j] = '\0';

}

int main(int argc, char* argv[])

{

char str[] = "abcdefgh";    // 注意,此处不能写成char *str = "abcdefgh";

printf("%s\n", str);

delChar(str, 'c');

printf("%s\n", str);

return getchar();

}

26、判断单链表中是否存在环(网上说的笔试题)

#include "stdafx、h"

typedef char eleType;       // 定义链表中的数据类型

typedef struct listnode     // 定义单链表结构

{

eleType data;

struct listnode *next;

}node;

node *create(int n)              // 创建单链表,n为节点个数

{

node *p = (node *)malloc(sizeof(node));

node *head = p;    head->data = 'A';

for(int i='B'; i<'A'+n; i++)

{

p = (p->next = (node *)malloc(sizeof(node)));

p->data = i;

p->next = NULL;

}

return head;

}

void addCircle(node *head, int n)    // 增加环,将链尾指向链中第n个节点

{

node *q, *p = head;

for(int i=1; p->next; i++)

{

if(i==n) q = p;

p = p->next;

}

p->next = q;

}

int isCircle(node *head)    // 这是笔试时需要写的最主要函数,其他函数可以不写

{

node *p=head,*q=head;

while( p->next && q->next)

{

p = p->next;

if (NULL == (q=q->next->next)) return 0;

if (p == q)

return 1;

}

return 0;

}

int main(int argc, char* argv[])

{

node *head = create(12);

addCircle(head, 8);         // 注释掉此行,连表就没有环了

printf("%d\n", isCircle(head));

return getchar();

}

6 难题(2道,难)

喝酒问题

由n元组(x1,x2,……,xn)组成的1个状态空间 E={(x1,x2,……,xn) | xi ∈Si, i=1,2,、、,n},给定关于n元组中的分量的1个约束集D,要求E中满足D的全部约束的所有n元组。其中Si是分量xi的定义域且|Si|有限,i=1,2,、、、n。我们称E中满足D的全部约束条件的任1n元组为问题P的1个解。

对于n元组(x1,x2,……,xn)中分量的约束,1般分为两类,1类是显约束,它给出对于n元组中分量的显式限制,比如当i≠j时xi≠xj;另1类是隐约束,它给出对于n元组中分量的隐式限制,比如:f(x1,x2,……,xn)≠ 0,其中f是隐函数。不过隐式显式并不绝对,两者可以相互转换。

解问题P的最朴素的方法是穷举法,即对E中的所有n元组,逐1地检测其是否满足D的全部约束。全部满足,才是问题p的解;只要有1个不满足,就不是问题P的解。显然,如果记m(i)=|S(i+1)|,i=0,1,、、、n-1,那么,穷举法需要对m=m(0)*m(1)*、、、*m(n-1)个n元组1个不漏地加以检测。可想而知,其计算量是非常之大的。

我们发现,对于许多问题,所给定的约束集D具有完备性,即i元组(x1,x2,……,xi)满足D中仅涉及到x1,x2,……,xi的所有约束意味着j(j<i)元组(x1,x2,……,xj)1定也满足D中仅涉及到x1,x2,……,xj的所有约束,i=1,2,……,n。换句话说,只要存在O≤j≤n-1,使得(x1,x2,……,xj)违反D中仅涉及到x1,x2,……,xj的约束之1,以(x1,x2,……,xj)为前缀的任何n元组(x1,x2,……,xj,……,xn)1定也违反D中仅涉及到又x1,x2,……,xi的1个约束,其中n≥i≥j。

这个发现告诉我们,对于约束集D具有完备性的问题P,1旦检测断定某个j元组(x1,x2,……,xj)违反D中仅涉及x1,x2,……,xj的1个约束,就可以肯定,以(x1,x2,……,xj)为前缀的任何n元组(x1,x2,……,xj,……,xn)都不会是问题的解,因而就不必去搜索它们、检测它们。回溯法正是针对这类问题,利用这类问题的上述性质而提出来的比穷举法效率高得多的算法。

回溯法首先将问题P的n元组的状态空间E表示成1棵高为n的带权有序树T,将在E中求问题P的所有解转化为在T中搜索问题P的所有解。树T类似于检索树。它可这样构造:设Si中的元素可排成x(i,1),x(i,2),……,x(i,m(i-1)),i=1,2,……,n。从根开始,让T的第i层的每1个结点都有m(i)个儿子。这m(i)个儿子到它们的共同父亲的边,按从左到右的次序分别带权x(i+1,1),x(i+1,2),……,x(i+1,m(i)),i=0,1,2,……,n-1。照这种构造方式,E中的1个n元组(x1,x2,……,xn)对应于T中的1个叶结点,T的根到这个叶结点的路上依次的n条边分别以x1,x2,……,xn为其权,反之亦然。另外,对于任意的0≤i≤n-1,E中n元组(x1,x2,……,xn)的1个前缀i元组(x1,x2,……,xi)对应于T中的1个非叶结点,T的根到这个非叶结点的路上依次的i条边分别以了x1,x2,……,xi为其权,反之亦然。特别,E中的任意1个n元组的空前缀(),对应于T的根。

因而,在E中寻找问题P的1个解等价于在T中搜索1个叶结点,要求从T的根到该叶结点的路上依次的n条边相应带的n个权x1,x2,……,xn满足约束集D的全部约束。在T中搜索所要求的叶结点,很自然的1种方式是从根出发逐步深入,让路逐步延伸,即依次搜索满足约柬条件的前缀1元组(xl),前缀2元组(xl,x2),前缀i元组(x1,x2,……,xi),……,直到i=n为止。注意,在这里,我们将(x1,x2,……,xi)应该满足的D中仅涉及x1,x2,……,xi的所有约束当做判断(x1,x2,……,xi)是问题p的解的必要条件,只有当这个必要条件加上条件i=n才是充要条件。为了区别,我们称使积累的判别条件成为充要条件的那个条件(如条件i=n)为终结条件。

在回溯法中,上面引入的树T被称为问题P的状态空间树;树T上的任意1个结点被称为问题p的状态结点;树T上的任意1个叶结点被称为问题P的1个解状态结点;树T上满足约束集D的全部约柬的任意1个叶结点被称为问题P的1个回答状态结点,简称为回答结点或回答状态,它对应于问题P的1个解。

示例8皇后问题,就是要确定1个8元组(x1,x2,、、,x8),xi表示第i行的皇后所在的列,这样的问题很容易应用上面的搜索树模型;然而,有些问题的解无法表示成1个n元组,因为事先无法确定这个n是多少,比如这个喝酒问题,问题的解就是1系列的倒酒喝酒策略,但是事先无法确定究竟需要进行多少步;还有著名的8数码问题(文曲星上的那个9x9方格中移数字的游戏),那个问题也是预先不知道需要移动多少步才能达到目标。不过这并不影响回溯法的使用,只要该问题有解,1定可以将解用有限的变元来表示,我们可以假设n就是问题的1个解的变元的个数,这样就可以继续利用上面的搜索树模型了。事实上,这棵搜索树并非预先生成的,而是在搜索的过程中逐步生成的,所以不知道树的深度n并不影响在树中搜索叶子节点。但是有1点很重要,如果问题根本不存在有限的解,或者问题的状态空间无穷大,那么沿着某条道路从根出发搜索叶节点,可能永远无法达到叶结点,因为搜索树会不断地扩展,然而叶结点也许是确实存在的,只要换1条道路就可以找到,只不过1开始就走错了路,而这条错路是永远无法终止的。为了避免这种情况我们1般都规定状态空间是有限的,这样即使搜索整个状态空间的每个状态也可以在有限时间内完成,否则的话回溯法很可能不适用。

搜索树的每1个节点表示1个状态,节点i要生成节点j必须满足约束集D中的约束条件,我们也可以将这个约束条件称为“状态转移要求”或者“产生要求”(意指从节点i产生节点j的要求,这是从“产生式系统”理论的角度来解释回溯法)。因此回溯法的实质是在1个状态空间中,从起始状态(搜索树的根)搜索到1条到达目标状态(搜索树的叶结点)的路径(就和走迷宫差不多,这是从图论的角度来解释回溯法)。1般来说,为了防止搜索的过程中出现回路,必须记录已经走过的节点(状态),在同1条路径中不能重复走过的节点(状态),这样只要状态空间是有限的,回溯法总是可以终止的。

===========================================================================================

下面我们就根据回溯法来解决这个喝酒问题

(1)状态的表示

1个状态用1个7元组表示 X=(x1,x2,x3,x4,x5,x6,x7);,其中x1~x3分别表示a,b,c三个酒瓶中的酒,x4~x7分别表示A,B,C,D四个人已经喝的酒;

(2)约束条件

1。每个人喝的酒不能超过4两;

2。每个瓶中容纳的酒不能超过该瓶的容量;

为了方便设第k个人喝的酒不超过C[k], 第i个酒瓶的容量为C, 则

C[1]=C[2]=8, C[3]=3, C[4]=C[5]=C[6]=C[7]=4;

约束条件为

0<= X <= C;

(3)状态的转移要求(状态产生要求)

从某个状态X转移到另1个状态Y有以下几种情况:

1。i瓶中的酒倒入j瓶中,并将j瓶装满:   Y = X - (C[j]-X[j]) ,  Y[j] = C[j],  i,j∈[1,3]

2。i瓶中的酒倒入j瓶中,并将i瓶倒空:   Y = 0 ,   Y[j] = X[j] + X   ,  i,j∈[1,3]

3。某个人j喝光了i瓶中的酒: Y = 0; Y[j] = X[j] +  X,    i∈[1,3], j∈[4,7]

当然状态Y必须满足(2)中的约束条件;

(4)初始状态

a,b两个瓶中装满酒,c中为空:  X0[1]=C[1], X0[2]=C[2], X0[3]=C[3], X0[4]=X0[5]=X0[6]=X0[7]=0;

(5)目标状态

所有的瓶中的酒为空,每个人都喝饱了酒:    Xn[1]=Xn[2]=Xn[3]=0 , Xn[4]=C[4],  Xn[5]=C[5], Xn[6]=C[6], Xn[7]=C[7];

下面给出1个通用的回溯法伪代码:

void DFS_TRY( s )

{

if (状态s是目标状态) {

打印结果;

退出;       // 如果要求输出所有的解,这里退出函数,如果只要求输出1组解,这里退出整个程序

}

for 从状态s根据产生要求产生的每个状态t

if (t不在堆栈中) {

状态t压入堆栈;

DFS_TRY(t);

状态t弹出堆栈;

}

}

主程序为:

初始状态s0压入堆栈;

DFS_TRY(s0);

然而,对于这个问题,如果单纯地用上面的回溯法解决效率非常的低,几乎无法忍受。所以要改进1下。我们注意到每个状态是1个7元组,而且根据约束条件,所有的合法的状态的个数是8*8*3*4*4*4*4 =49152个,完全可以将所有的状态记录下来,即使穷举所有的状态也是可以忍受的。所以在上面的DFS_TRY中,我们不是在堆栈中寻找已经搜索过的状态,而是在1个状态表中找已经搜索过的状态,如果某个状态在状态表中的标志表明该状态已经搜索过了,就没有必要再搜索1遍。比如,单纯的回溯法搜索出来的搜索树如下所示:

a

/ \

/   \

b     c

\   /

\ /

d

/ \

/   \

从a出发,搜索 a - b - d - 、、、 然后回溯到a, 又搜索到 a - c - d - 、、、, 因为d在搜索的路径上并没有重复,所以在堆栈中是发现不了d节点被重复搜索的,这样就重复搜索了d和它的子树;如果用1个表格纪录每个节点是否被搜索过了,这样搜索 a - b - d - 、、、回溯到a, 又搜索到 a - c - d ,这时候查表发现d已经搜索过了,就可以不用再搜索d和它的子树了。

这种用1个表格来记录状态的搜索策略叫做“备忘录法”,是动态规划的1种变形,关于动态规划和备忘录法,请参见:

http://algorithm、myrice、com/algorithm/technique/dynamic_programming/index、htm

备忘录法的伪代码:

bool Memoire_TRY( s )

{

if (状态s是目标状态) {

记录状态s;

return true;       // 这里假设只要求输出1组解

}

for 从状态s根据产生要求产生的每个状态t

if (状态t没有被搜索过) { // 注意这里的改变

标记状态t被访问过;

if (DFS_TRY(t)) {

记录状态s;

return true;

}

}

return false;

}

主程序为:

初始化设置状态表中的所有状态未被访问过

初始状态设为s0;

if (Memoire_TRY(s0))

打印记录下来的解;

这样就不需要自己设置堆栈了,但是需要维护1个状态访问表。

下面是按照这种思路写的程序,注意,求出来的不是最优解,但是很容易修改该程序求出最优解。

#include <iostream、h>

#include <string、h>

const int CUP_COUNT   = 3;  // 酒杯的数目

const int STATE_COUNT = 7;  // 状态变量的维数

typedef int State[STATE_COUNT];     // 记录状态的类型

const State CONSTR = {8, 8, 3, 4, 4, 4, 4}; // 约束条件

const State START = {8, 8, 0, 0, 0, 0, 0}; // 初始状态

const State GOAL = {0, 0, 0, 4, 4, 4, 4}; // 目标状态

const int MAX_STATE_COUNT = 10*10*10*10*10*10*10; //态空间的状态数目

const MAX_STEP = 50;  // 假设最多需要50步就可以找到目标

const State key = {3, 5, 3, 3, 2, 0, 0};

bool visited[MAX_STATE_COUNT]; // 用来标记访问过的状态

State result[MAX_STEP];  // 记录结果;

int step_count = 0;  // 达到目标所用的步数

// 计算状态s在状态表中的位置

int pos(const State &s)

{

int p = 0;

for (int i=0; i<STATE_COUNT; i++) {

p = p*10 + s;

}

return p;

}

// 判断状态a,b是否相等

bool equal(const State &a, const State &b) {

for (int i=0; i<STATE_COUNT; i++)

if (a!=b) return false;

return true;

}

void printState(const State &s) {

for (int i=0; i<STATE_COUNT; i++)

cout << s << " ";

cout << endl;

}

// 备忘录法搜索

bool Memoire_TRY(const State &s, int step)

{

if (memcmp(s,GOAL,sizeof(s))==0) {  // 如果是目标状态

step_count = step;

memcpy(result[step-1],s, sizeof(s)); //  记录状态s

return true;

}

int i, j;

// 第1种要求,第i个人喝光杯子j中的酒

for (i=CUP_COUNT; i<STATE_COUNT; i++)

if (s < CONSTR)    // 如果第i个人还可以喝

for (j=0; j<CUP_COUNT; j++)

if (s[j]>0 && s + s[j] <= CONSTR) {  // 如果第i个人可以喝光第j杯中的酒

State t;

memcpy(t, s, sizeof(s));

t += t[j];     // 第i个人喝光第j杯的酒

t[j] = 0;

int tmp = pos(t);

if (!visited[pos(t)]) {   // 如果状态t没有访问过

visited[pos(t)] =true;  // 标记状态t访问过了

if (Memoire_TRY(t, step+1)) { // 从状态t出发搜索

memcpy(result[step-1],s, sizeof(s)); //  记录状态s

return true;

} // end of if (Memoire_TRY(t, step+1))

} // end of if (!visited[pos(t)])

} // end of if (s + s[j] <= CONSTR)

// 第2种要求,将杯子i中的酒倒入到杯子j中去

for (i=0; i<CUP_COUNT; i++)

for (j=0; j<CUP_COUNT; j++)

if (i != j) {

int k = (CONSTR[j] - s[j] < s ? CONSTR[j] - s[j] : s ); // 计算出可以从i中倒入j中的酒的数量

if (k > 0) {  // 如果可以倒

State t;  // 生成新的状态t

memcpy(t, s, sizeof(s));

t -= k;

t[j] += k;

int tmp = pos(t);

if (!visited[pos(t)]) {  // 如果状态t没有访问过

visited[pos(t)] =true; // 标记状态t访问过了

if (Memoire_TRY(t, step+1)) { // 从状态t出发搜索

memcpy(result[step-1],s, sizeof(s)); //  记录状态s

return true;

} // end of if (Memoire_TRY(t, step+1))

} // end of if (!visited[pos(t)])

} // end of if (k > 0)

} // end of if (i != j)

return false;

} // end of Memoire_TRY

void main()

{

memset(visited, false, sizeof(visited));

if (Memoire_TRY(START,1)) {

cout << "find a solution: " << endl;

for (int i=0; i<step_count; i++) {

for (int j=0; j<STATE_COUNT; j++)

cout << result[j] << " ";

cout << endl;

}

} else

cout << "no solution、" << endl;

}

鹰蛋

269道各路算法考试题集锦相关推荐

  1. JAVA 判断简单密码算法_十道简单算法题二【Java实现】

    前言 清明不小心就拖了两天没更了-- 这是十道算法题的第二篇了-上一篇回顾:十道简单算法题 最近在回顾以前使用C写过的数据结构和算法的东西,发现自己的算法和数据结构是真的薄弱,现在用Java改写一下, ...

  2. python面试题及答案-50道Python面试题集锦(附答案)

    原标题:50道Python面试题集锦(附答案) Python是目前编程领域最受欢迎的语言.在本文中,我将总结Python面试中最常见的50个问题.每道题都提供参考答案,希望能够帮助你在2019年求职面 ...

  3. DayDayUp:本博主预计2019下半年将会出两本书(关于人工智能算法及其实战案例应用方向、计算机算法竞赛集锦方向),如有合作意向,请留言告知

    DayDayUp:本博主预计2019下半年将会出两本书(关于人工智能算法及其实战案例应用方向.计算机算法竞赛集锦方向),如有合作意向,请留言告知 PS:禁止任何形式的知识盗取!! 目录 关于人工智能算 ...

  4. python全排序算法题_Python的100道经典算法题(1)

    按照c语言的100道经典算法题,自己原创写的,就得是自己的练习题了 [程序1] 题目:有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 程序分析:可填在百位.十位.个位的数 ...

  5. leetcode贪心算法题集锦(持续更新中)

    leetcode贪心算法题集锦 leetcode贪心算法题集锦(持续更新中).python 和C++编写. 文章目录 leetcode贪心算法题集锦 一.贪心算法 1.盛最多水的容器 2.买股票的最佳 ...

  6. 学习笔记之15道简单算法题

    15道简单算法题 http://www.cnblogs.com/hlxs/archive/2014/06/06/3772333.html (●-●) | 剑指Offer_编程题_牛客网 http:// ...

  7. 基于颜色分割的盲道识别算法

    基于颜色分割的盲道识别算法 前言   本任务的要求是通过相关算法识别出城市区域中的盲道,通过对各种盲道进行调研,发现目前城市中的盲道基本分为两大部分,一类是具有明显样色和纹理特征的盲道,通常是黄色(当 ...

  8. 十道简单算法题二【Java实现】

    前言 清明不小心就拖了两天没更了-- 这是十道算法题的第二篇了-上一篇回顾:十道简单算法题 最近在回顾以前使用C写过的数据结构和算法的东西,发现自己的算法和数据结构是真的薄弱,现在用Java改写一下, ...

  9. 有趣的110道LeetCode算法题小抄,势如破竹的面试

    前言 随着互联网寒潮的到来, 越来越多的互联网公司提高了面试的难度,其中之一就是加大了面试当中手撕算法题的比例.这里说的算法题不是深度学习,机器学习这类的算法,而是排序,广度优先,动态规划这类既考核数 ...

最新文章

  1. 最新Java中Date类型详解
  2. 信息检索顶会SIGIR 2021大奖出炉!山东大学荣获最佳学生论文
  3. CreateMutex创建互斥体可以用于只运行进程的一个实例
  4. iphone个系列尺寸_iPhone 12系列、11系列尺寸对比
  5. 嵌入式linux如何下载程序,Linux平台的下载程序-嵌入式系统-与非网
  6. 01_MUI之Boilerplate中:HTML5示例,动态组件,自定义字体示例,自定义字体示例,图标字体示例
  7. LeetCodeOJ. String to Integer (atoi)
  8. 详解javascript中的call, apply
  9. vscode调试redis源码
  10. JavaScript学习笔记(三)--操作运算符
  11. Scala中的match(模式匹配)
  12. Unicode和ASCII的区别
  13. Spring之自动装配注入
  14. pdf转换成word转换器2014注册码
  15. weiPe系统启动盘还原
  16. 拼音打字时不定时出现重复字母
  17. 套路(二):火星求生的经济节奏引导
  18. cpu,内存条,硬盘,显卡,主板,显示器之间的关系
  19. 2016全域大数据应用论坛11位嘉宾核心观点
  20. gif图片的体积怎么缩小?如何压缩动图大小?

热门文章

  1. 《程序员入职甲乙方公司的套路》。送给要入职的程序员们,避免踩坑。
  2. webservice使用的一些总结
  3. HTML5笔记+案例
  4. linux 查看glibc,Linux平台查看glibc版本
  5. 离散程度度量:平均差、方差、标准差
  6. Fzu 2202 犯罪嫌疑人【逻辑推理思维题】好题!
  7. 苏宁易购获得商品详情API,Onebound电商数据
  8. 51单片机“嘀嘀嘀”报警器
  9. ORACLE根据汉字返回拼音的包--强大
  10. Spring学习说明