zoukankan      html  css  js  c++  java
  • 算式转移

    算式转移

    题目描述

    给出一个仅包含加减乘除四种运算的算式(不含括号),如1+2*3/4,在保持运算符顺序不变的情况下,你可以进行若干次如下操作:
    如果交换相邻的两个数,表达式值不变,那么你就可以交换这两个数。
    现在你可以进行任意次操作,使得算式的数字序列字典序最小,然后输出结果,数字之间的字典序定义为若a<b,则a的字典序小于b。
    

    输入

    第一行包括一个整数n,表示算式的长度,即包含n个数字和n-1个运算符。(1<=n<=100000)。
    第二行包括一个含有n个非0整数和n-1个运算符的算式,整数与运算符用空格隔开,运算符包括“+,-,*,/”。整数的绝对值不超过1000.
    

    输出

    按要求输出字典序最小的表达式,数字与符号之间用空格隔开。
    

    样例输入

    6
    3 + 2 + 1 + -4 * -5 + 1
    

    样例输出

    1 + 2 + 3 + -5 * -4 + 1
    

    分析:

    1、可以考虑使用冒泡排序进行排列。以内在中间运算符号的顺序不变,只有数字的顺序变化,所以可能需要把输入字符串中的数字提取出来,可能有点麻烦。
    2、对不同的运算符间关系进行分析:

    • ‘-’和‘/’两端的数字顺序不能够颠倒;
    • '*'两端的数字可以颠倒,但如果前一个符号为‘/’则不可以;
    • '+'两端的数字可以颠倒,但如果后一个符号为‘/’或'*'则不可以;
    • 满足以上情况且当前符号和后一个符号相同,则可以颠倒。

    代码

    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    
    int main() {
    	int numMath = 8;
    	//cin >> numMath;
    	//因为上面cin>>numMath时缓冲区残留有回车,所以在下面getline时直接结束了.
    	//解决办法有很多: 
    	//cin.get();(读取回车, 忽略返回值)   或者cin.sync();(清空缓冲) 或者cin.ignore(1); (忽略一个字符)
    	//cin.get();
    	string strMath;
    	//getline(cin,strMath);
    	strMath = "30 + 200 + 10 / -4 * -50 * 10";
    	string strR; //用于返回
    	vector<int> NumArray;
    	vector<char> OpArray;
    	for (int i = 0; i < strMath.length(); i++) {
    		int Num = 0;
    		int temp = i; //记录进去之前的i的值
    		bool negFlag = false; //负数的标志
    		bool numFlag = false; //负数的标志
    		while (strMath[i] != ' '&&strMath[i] != '') {
    			if (strMath[i] != '+'&&strMath[i] != '*'&&strMath[i] != '/') {
    				if (strMath[i] == '-'&&strMath[i + 1] != ' ') {
    					negFlag = true;
    				}
    				else if (strMath[i] >= '0'&&strMath[i] <= '9') {
    					Num = Num * 10 + (strMath[i] - '0');
    					numFlag = true;
    				}
    				else if (strMath[i] == '-'&&strMath[i + 1] == ' ') {
    					OpArray.push_back(strMath[i]);
    				}
    			}
    			else {
    				OpArray.push_back(strMath[i]);
    			}
    			i++;
    		}
    		if (negFlag) {
    			NumArray.push_back(0 - Num);
    		}
    		else if(numFlag)
    			NumArray.push_back(Num);
    	}
    
    	for (int i = 0; i < NumArray.size(); i++) {   //含特定条件的冒泡排序
    		for (int j = 0; j < NumArray.size() - i - 1; j++) {
    			if (j < OpArray.size() - 1) {
    				if (NumArray[j] > NumArray[j + 1] && (OpArray[j] != '-' || OpArray[j] != '/') && (OpArray[j] == OpArray[j + 1])
    					&& (OpArray[j]=='*'&&OpArray[j-1]!='/'&&j>=1)) {
    					int temp = NumArray[j];
    					NumArray[j] = NumArray[j + 1];
    					NumArray[j + 1] = temp;
    				}
    			}
    			else {
    				if (NumArray[j] > NumArray[j + 1] && (OpArray[j] != '-' || OpArray[j] != '/') && (OpArray[j] == OpArray[j - 1])) {//对于最后一个符号的判断
    					int temp = NumArray[j];
    					NumArray[j] = NumArray[j + 1];
    					NumArray[j + 1] = temp;
    				}
    			}
    		}
    	}
    	for (int i = 0; i < NumArray.size() - 1; i++) {
    		strR += to_string(NumArray[i]);
    		strR += " ";
    		strR += OpArray[i];
    		strR += " ";
    	}
    	strR += to_string(*(NumArray.end() - 1));
    	cout << strR;
    	return 0;
    }
    

    输出:

    30 + 200 + 10 / -4 * -50 * 10
    

    原题中的最大数字个数为100000个,本程序方法的复杂度为(105)2 = 1010,在C/C++中一般1秒钟运算107~10^8次,因此可能在实际中可能会导致程序运算超时(>1s)。欢迎各位大神提供更加好的优化方案。

  • 相关阅读:
    找不到或无法加载主类
    Syntax error , insert “EnumBody” to complete EnumDeclaration
    The type javax.servlet.http.HttpServletRequest cannot be resolved. It is indirectly referenced from required .class files
    003 Fiddler 界面
    002 Fiddler 配置
    001 Fiddler 安装
    C++的函数重载
    001 位运算
    【纪中受难记】——C2Day2:dp不能
    连续函数的根
  • 原文地址:https://www.cnblogs.com/hellovan/p/11422690.html
Copyright © 2011-2022 走看看