ACM水题-AB串(AC,分情况,要小心陷阱,两种思路)

AB串
Time Limit:1000MS  Memory Limit:32768K

Description:

对一个AB串,进行一定的操作,每次操作只能交换相邻的字符。求最少的操作数使得相同的字母都在同一边,如AAAAABBBBB。

Input:

每一行给出一个AB串,长度不超过100,且A、B都含有,不含其它字符

Output:

每一行一个答案,输出最少操作次数。

Sample Input:

ABA

Sample Output:

1

Source:

李广为

Status   Submit

 

链接:http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1518

 

 

/*	--------------------------------------------------------------------------------
	WA了,原因就是中陷阱了,ABA,操作步数1,但是结果有可能有两种,ABB,BBA。。
	我的代码是以ABBB这样为基础的,所以错了。。。明天再改。。下午要复习了,要考试了。。
	ACM月赛也木有玩了~~~


    AC,分两种情况来讨论,一种就是A左B右,一种就是B左A右,两个之中求最小的那个。。
	15MS
	--------------------------------------------------------------------------------	*/


#include<stdio.h>
#include<string.h>

char szStr[104] ;

int nMinStep(int nStart, int nFirst , char chLeft, char chRight) ; 

int main(void)
{
	int i = 0 ;
	int nFirstB = 0 ;
	int nFirstA = 0 ;
	int nMinAB = 0 ;
	int nMinBA = 0 ;
	int nMinTotal = 0 ;
	char chTemp = 0 ;
	int iA = 0 ;
	int iB = 0 ;

	while(scanf("%s",szStr) != EOF)
	{	
		nMinTotal = 0 ;
		nFirstB = -1 ;
		nFirstA = -1 ;
		i = 0 ;

		while(szStr[i] != '\0')
		{
			if(nFirstA >= 0 && nFirstB >= 0)
			{
				break ;
			}
			else if('A' == szStr[i] && nFirstA < 0)
			{
				nFirstA = i ;
				iA = i + 1 ; 
			}
			else if('B' == szStr[i] && nFirstB < 0)
			{
				nFirstB = i ;
				iB = i + 1 ;
			}
			i++ ;
		}

		nMinAB =  nMinStep(iB,nFirstB,'A','B') ;
		nMinBA = nMinStep(iA,nFirstA,'B','A')  ;
		nMinTotal = nMinAB < nMinBA ? nMinAB : nMinBA ;

		printf("%d\n",nMinTotal) ;
	}	
	return 0 ;
}

int nMinStep(int nStart, int nFirst , char chLeft, char chRight) 
{
	int i = nStart ;
	int j = 0 ; 
	int nTotal = 0 ;
	
	char szTempStr[104] ;
	char chTemp ;

	strcpy(szTempStr,szStr) ;

	while(szTempStr[i] != '\0')
	{
		if(chRight == szTempStr[i])
		{
			i++ ;
		}
		else if(chLeft == szTempStr[i])
		{
			chTemp = szTempStr[i] ;
			for(j = i ; j > nFirst ; --j)
			{
				szTempStr[j] = szTempStr[j-1] ;
				nTotal++ ;
			}
			szTempStr[nFirst] = chTemp ;
			nFirst++ ;
		}
	}
	return nTotal ;
}







 

/*	----------------------------------------------------------------------------------------
	第二种方法:

	其实就是看看排前要移动的字母前面的互异字母有多少个。
	比如
	ABBBAA
	如果A在左,B在右的话。那个在第二个A的前面有3个B,所以A最少要移动3次。同样道理排在第3个A
	前面也有3个B,所以最小也要移动3次,所以这种情况下是6步。
	如果B在右,A在左的话。那么排在第一个B前面有一个A,所以第一个B最少要移动1次。同样道理
	第二、第三个B都至少要移动1次。所以总共是三次。

    我的算法思路就是遍历一次数组,统计上述算法需要的信息。即在发现A之前,排在它前面有多少个
	B或者在发现B之前,排在它前面有多少个A。

    所以相对第一种算法来说,时间复杂度降低了一个常数因子,为O(n),前一种算法就算不计找到第一
	个A,B,不计复制字符串的时间至少也要O(2n)的时间。
	前一种算法的总时间为 :15MS
	而这一种只需要: 4 MS

	----------------------------------------------------------------------------------------	*/


#include<stdio.h>

char szStr[104] ;

int main(void)
{
	int i = 0 ;
	int nFirstB = 0 ;
	int nFirstA = 0 ;
	int nMinAB = 0 ;
	int nMinBA = 0 ;
	int nMinTotal = 0 ;
	int nASum = 0 ;
	int nBSum = 0 ;
	int fFA = 0 ;
	int fFB = 0 ;

	while(scanf("%s",szStr) != EOF)
	{	
		nMinTotal = 0 ;
		nFirstB = -1 ;
		nFirstA = -1 ;
		nMinAB = nMinBA = 0 ;
		nASum = nBSum = 0 ;
		fFA = fFB = 0 ;
		i = 0 ;

		while(szStr[i] != '\0')
		{
			if('A' == szStr[i])
			{
				if(nFirstA < 0)
				{
					nFirstA = i ;
					nASum++; 
				}
				else 
				{
					nASum++ ;
				}
				if(nFirstB >=0)
				{
					nMinAB += nBSum ;
				}
			
			}
			else if('B' == szStr[i] )
			{
				if(nFirstB < 0)
				{
					nFirstB = i ;
					nBSum++;
				}
				else
				{
					nBSum++ ;
				}	
				if(nFirstA >= 0)
				{
					nMinBA += nASum ;
				}
				
			}
			i++ ;
		}
		nMinTotal = nMinAB < nMinBA ? nMinAB : nMinBA ;
		printf("%d\n",nMinTotal) ;
	}	
	return 0 ;
}








 

/*	--------------------------------------------
	这一个方法是建立在第二种方法上的,但是没有使用数组,所以空间复杂度应该有所下降,但是测试
	结果却和有数组的一样。。。。。
	而且在最后一组测试数据后面竟然木有换行符,直接EOF,所以我的代码最后还要加上一个特殊处理

	时间:4MS,190K
	

	-------------------------------------------- */

#include<stdio.h>

int main(void)
{
	int nFirstB = 0 ;
	int nFirstA = 0 ;
	int nMinAB = 0 ;
	int nMinBA = 0 ;
	int nMinTotal = 0 ;
	int nASum = 0 ;
	int nBSum = 0 ;
	int fNewLine = 1 ;
	char ch = '\0' ;
	
	while((ch = getchar()) != EOF)
	{
		if(1 == fNewLine)
		{
			nMinTotal = 0 ;
			nFirstB = nFirstA = -1 ;
			nMinAB = nMinBA = 0 ;
			nASum = nBSum = 0 ;
		}
		if('\n' == ch)
		{
			nMinTotal = nMinAB < nMinBA ? nMinAB : nMinBA ;
			printf("%d\n",nMinTotal) ;
			fNewLine = 1 ;
			continue ;
		}
		
		fNewLine = 0 ;
		if('A' == ch)
		{
			if(nFirstA < 0)
			{
				nFirstA = 1 ;
				nASum++; 
			}
			else 
			{
				nASum++ ;
			}
			if(nFirstB >=0)
			{
				nMinAB += nBSum ;
			}
			
		}
		else if('B' == ch)
		{
			if(nFirstB < 0)
			{
				nFirstB = 1 ;
				nBSum++;
			}
			else
			{
				nBSum++ ;
			}	
			if(nFirstA >= 0)
			{
				nMinBA += nASum ;
			}		
		}
	}

	/*加上这一行是因为,那个最一个测试数据后面竟然不加换行符...*/
	nMinTotal = nMinAB < nMinBA ? nMinAB : nMinBA ;     
	printf("%d\n",nMinTotal) ;
	return 0 ;
}





 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值