[ACM]#POJ#2895

POJ 2895 题解
本文提供了解决POJ 2895问题的两种C++实现方案,包括字符处理和时间计算的详细算法。通过优化输入方式,探讨了不同方法对程序运行效率的影响。

http://poj.org/problem?id=2895

//Version 1
#include <iostream>
#include <stdlib.h>
#include <string.h>

int No_2895(); 

int main(int argc, char** argv) {
	No_2895();	
	return 0;
}

int No_2895(){	
	int testCaseNumber;
	int p,w;
	int result;
	
	char preChar;
	char curChar;	
	char preCharFlag = '0'; //FLAG, 标识字符是否属于A到Z; 0表述不属于,1表示属于; 
	char curCharFlag = '1';
	
	int pressTimes = 0;
	
	char LookupTable[26]={  //字母相关关系表,例如映射A为0,B为1,通过查表,可以知道A和B 都对应‘2’ 
	'2','2','2',// A,B,C 	
	'3','3','3',// D,E,F
	'4','4','4',// G,H,I 
	'5','5','5',// J,K,L
	'6','6','6',//M,N,O
	'7','7','7','7',//P,Q,R,S
	'8','8','8',    //T,U,V
	'9','9','9','9' //W,X,Y,Z
	};
	
	int inputCountTable[26]={  //按键次数查询表
	1,2,3,// A,B,C 	
	1,2,3,// D,E,F
	1,2,3,// G,H,I 
	1,2,3,// J,K,L
	1,2,3,//M,N,O
	1,2,3,4,//P,Q,R,S
	1,2,3,    //T,U,V
	1,2,3,4, //W,X,Y,Z
	};
	
	scanf("%d",&testCaseNumber);
	
	while(testCaseNumber--){
		scanf("%d %d\n",&p,&w);		
		result = 0;
		preChar = ' '; // 每次输入新的一行字符前,将第一个字符的preChar(前一个字符)设置成空格; 
		preCharFlag = '0'; //FLAG, 标识字符是否属于A到Z; 0表述不属于,1表示属于; 
		curCharFlag = '1';
		
		//Todo:
		//这里可以进一步改进一下:对于输入字符串,不用getchar,减少调用IO的次数,看看时间是否能减少。
		do{
			curChar = (char)getchar(); 
			if(curChar =='\n'){						
				break;
			} 
			
			/* 
			   检查当前字符是否和前一个字符相关,如果相关,需要等待w毫秒。
			   相关的条件:1.当前字符属于 A-Z,2.前一个字符属于A-Z;3.两个字符的lookuptable一样; 
			*/			
			if( 'A'<=curChar && curChar<='Z'){
				curCharFlag = '1';
			} else{
				curCharFlag = '0';
			}			
		
			if (curCharFlag == '1' &&  //curChar属于A-Z 
			    preCharFlag == '1' &&  //preChar属于A-Z 
				(LookupTable[curChar-'A']==LookupTable[preChar-'A'])//两个字符相关 
				){
					result+=w;					
			}
			if (curCharFlag == '1'){
				pressTimes = inputCountTable[curChar-'A'];
			}else{
				pressTimes = 1;	
			}
			
			result +=p*pressTimes; //输入一个字符需要多个P毫秒;
				
			preChar = curChar;
			preCharFlag = curCharFlag;
			pressTimes = 0;
		}while(1);
		
		printf("%d\n",result);
	} 
	
	return 0;
}

//Version 2,使用gets直接输入一行,貌似没有通过减少IO次数,提高运行效率
#include <iostream>
#include <stdlib.h>
#include <string.h>

int No_2895(); 
int getResult(int p,int w);

int main(int argc, char** argv) {
	No_2895();	
	return 0;
}

/*
处理一行字符串,其中只包含空格和英文大写字母。返回处理这行字符串需要的时间。 
*/
int getResult(int p,int w){
		 
	char LookupTable[26]={  //字母相关关系表,例如映射A为0,B为1,通过查表,可以知道A和B 都对应‘2’ 
		'2','2','2',  // A,B,C 	
		'3','3','3',  // D,E,F
		'4','4','4',  // G,H,I 
		'5','5','5',  // J,K,L
		'6','6','6',  // M,N,O
		'7','7','7','7',//P,Q,R,S
		'8','8','8',    //T,U,V
		'9','9','9','9' //W,X,Y,Z
	};
	
	int inputCountTable[26]={  //按键次数查询表
		1,2,3,  // A,B,C 	
		1,2,3,  // D,E,F
		1,2,3,  // G,H,I 
		1,2,3,  // J,K,L
		1,2,3,  // M,N,O
		1,2,3,4,// P,Q,R,S
		1,2,3,  // T,U,V
		1,2,3,4,// W,X,Y,Z
	};	

	char preCharFlag = '0'; //FLAG, 标识字符是否属于A到Z; 0表述不属于,1表示属于; 
	char curCharFlag = '1';

	char tempString[1000]; //题目说明,字符串最大1000个字符。
	
	///////////////////         从这里开始了!     /////////////////// 	
	int result = 0;	
	//输入一行的例子:1 3   789 B
	memset(tempString,0,1000);
	if(!gets(tempString)){
		return 0;
	}	
	int stringLength = strlen(tempString);
	
	//处理第一个字符:
	result += p*inputCountTable[tempString[0]-'A'];
	preCharFlag = '1'; //因为题设说明开头没有空白,所以肯定是大写字母,这里的flag是‘1’ 
	
	//从第二个字符到最后一个字符,依次处理 
	for(int i = 1;i<stringLength;i++){
		if(tempString[i]==' '){  //如果是空格,则 flag 为0; 
			curCharFlag = '0';			
		}else{
			curCharFlag = '1';
		}
		
		//判断当前字符和前一个字符的相关性:
		if (curCharFlag == '1' &&  //curChar属于A-Z 
			preCharFlag == '1' &&  //preChar属于A-Z 
			(LookupTable[tempString[i]-'A']==LookupTable[tempString[i-1]-'A'])//两个字符相关 
		){
			result+=w;					
		} 
		
		if (curCharFlag == '1'){ //如果字符是A-Z,计算时间时需要考虑按了几次;		 
				result += p * inputCountTable[tempString[i]-'A'];
		}else{
				result += p;
		}
		
		preCharFlag = curCharFlag;		
	}
	
	 
	return result; 
}

int No_2895(){	
	int testCaseNumber;
	int p,w;
	int result;
	
	scanf("%d",&testCaseNumber);	
	while(testCaseNumber--){
		scanf("%d %d\n",&p,&w);
		result = getResult(p,w);
		printf("%d\n",result);
	} 
	
	return 0;
}

/*
使用gets不用scanf的原因是,scanf在出入带有空格的字符串时需要自己考虑比较多的情况,使用麻烦。
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值