数据结构题目汇总

本文探讨了判断序列是否为栈混洗的算法实现,并通过KMP算法的next数组来推导模式字符串的问题。给出了具体实例及代码实现,要求O(N)时间复杂度解决栈混洗问题,同时分析next数组合法性以恢复模式字符串。
摘要由CSDN通过智能技术生成

1.判断栈混洗

total submissions: 909times

passed: 421times

passing rate: 46.31%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

判断一个输入序列是否为某一个序列的栈混洗。设输入序列为1-N的数字。

输入:

n,随后输入一个包含n个数字序列。范围从1到n的不同数字

输出:

如果是合法的栈混洗输出ture,否则输出false;

要求O(N)时间复杂度

sample inpput and output

样例1

input:

7
3 4 2 1 5 6 7

output:

true

样例2

input:

6
5 4 3 1 2 6

output:

false

#include<iostream>
#include<stack>
using namespace std;

int main() 
{
	int n;
	cin >> n;
	int* data = new int[n];
	for (int i = 0; i < n; i++)
		cin >> data[i];
	stack<int>s;

	for (int i = 1; i < data[0]; i++)
		s.push(i);
	int tmp = data[0];
	for (int i = 1; i < n; i++) 
	{
		if (!s.empty()) 
		{
			if (data[i] == s.top())s.pop();//当前元素与栈顶元素相同时,取出栈顶元素 
			else if (data[i] > s.top())//当前元素大于栈顶元素,则让后续数字入栈 
				for (int j = tmp + 1; j < data[i]; j++)
					s.push(j);
			else if (data[i] < s.top()) //当前元素小于栈顶元素,则不可能有这样的出栈顺序 
			{
				cout << "false" << endl;
				return 0;
			}
		}
	}
	cout << "true" << endl;
	return 0;
}

2

根据next数组推导模式字符串

total submissions: 1960times

passed: 475times

passing rate: 24.23%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

根据KMP算法的next数组值,推断模式字符串。

假设模式字符串中只存在0,1两种字符。给出首字符和next数组。请输出模式字符串。如果next数组不合法则输出ERROR

Input Format

先输入模式字符串首字符0或者1,然后输入尾字符0或者1

再输入 模式字符串长度n,n<=30

最后输入n个以 -1,0,起始的整数。

Output Format

模式字符串 或者 ERROR 

Example

Input

1 0 10

-1 0 1 2 3 4 0 1 2 3

Output

1111101110

Input

1 1 6

-1 0 0 0 0 0

Output

100001

Input

1 1 6

-1 0 2 0 0 0

Output

ERROR

说明

以传统未优化的KMP算法推导的next数组。

sample inpput and output

样例1

input:

1 1 6

-1 0 0 0 0 0

output:

100001

样例2

input:

1 1 6
-1 0 2 0 0 0

output:

ERROR

样例3

input:

1 1 7
-1 0 1 2 3 4 2

output:

ERROR

#include <iostream>
using namespace std;

int kmp(int* next, int f, int l, int n) 
{
	int cur;
	int* tmp = new int[n];//用于暂存模式字符串
	tmp[0] = f; 
	for (int i = 2; i < n; i++) 
	{
		if (next[i] == 0)//最大匹配长度为0
		{
			if (f == 1) cur = 0;//当前字符的前一个字符与首字符相异 
			else cur = 1;
		}
		else 
		{
			if (next[i] >= i || ( i != next[i] + 1 && tmp[i - next[i] - 1] == tmp[0])) //错误:最大匹配长度过长或字符不匹配时不能回溯到正确位置  
			{
				cout << "ERROR" << endl;
				return 0;
			}
			cur = tmp[next[i] - 1];
		}
		tmp[i - 1] = cur;
	}
	for (int i = 0; i < n - 1; i++)
	{
		cout << tmp[i];
	}
    cout << l;
    cout << endl;
    delete[]tmp;
    return 0;
}
int main() 
{
	int f, l, n;
	cin >> f >> l >> n;
	int* next = new int[n];
	for (int i = 0; i < n; i++)
		cin >> next[i];
	kmp(next, f, l, n);
	delete[]next;
	return 0;
}

3

互斥字符串

total submissions: 1000times

passed: 413times

passing rate: 41.30%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

给定一个仅含有英文大小写字母的字符串序列 s,若其中任意两个相邻字符都不是同一个字母的大小写形式,则称其为互斥字符串

程序需要将给定的字符串转换为互斥字符串。aa为互斥,aA和Aa为非互斥。

程序的每次操作可以从字符串中选出满足上述条件的两个相邻字符并删除,直到字符串整理好为止。

注:若最终结果为空字符串,请输出 -1。

要求时间复杂度O(n)

Input Format

输入由一行字符串组成。测试样例保证答案唯一。

Output Format

输出一行,为输入字符串经过若干次删除操作得到的互斥字符串。

Example

Input

abBAcCc

Output

c

说明

该样例存在多种转换路径,但最终输出相同

"abBAcCc" --> "aAcCc" --> "cCc" --> "c"

"abBAcCc" --> "abBAc" --> "aAc" --> "c"

sample inpput and output

样例1

input:

abBAcCc

output:

c

样例2

input:

AaBbCcDd

output:

-1

#include<iostream>
#include<string>
using namespace std;
bool isCap(char c1, char c2)
{
    return abs(c1 - c2) == 'a' - 'A';
}
int main()
{
    string s;
    cin >> s;
    char * temp=new char[s.size()+1];
    temp[s.size()] = '\0';
    int top = -1;
    for (int i = 0; i < s.size(); i++)
    {
        if (top ==-1 ||!isCap(temp[top], s[i]))
        {
            temp[++top] = s[i];
        }
        else
        {
            temp[top--] = '\0';
        }
    }
    if (top ==-1)
    {
        cout << top;
    }
    else
    {
        cout << temp << endl;
    }
}

4

旋转的矩阵

total submissions: 1102times

passed: 422times

passing rate: 38.29%

memory limit: 104857600(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

给定一个n*m的矩阵,请以顺、逆时针交替旋转的方式打印出每个元素。

  

Input Format

第一行n m; 0<n,m<100

后n行,每行m个整数。

Output Format

n*m个矩阵元素,空格隔开。

Example

Input

4 4

1  2  3  4

12 13 16  5

11 14 15  6

10  9  8  7

Output

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Input

3 4

1  2  3  4

10 11 12  5

9  8  7  6  

Output

1 2 3 4 5 6 7 8 9 10 11 12

说明

sample inpput and output

样例1

input:

1 3
3 4 1

output:

3 4 1

样例2

input:

4 4
1  2  3  4
12 13 16  5
11 14 15  6
10  9  8  7

output:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

样例3

input:

3 1
6
5
7

output:

6 5 7

#include<iostream>
#include<vector>
using namespace std;
int main()
{
    int m, n;
    while(cin >> m >> n)
    {
        vector<vector<int>> res(m, vector<int>(n));
        for(int i = 0; i < m; i++)
        {
        	for (int j = 0; j < n; j++) cin >> res[i][j];
		}

        int row = res.size();
        int col = res[0].size();
        int left = 0, right = col-1, top = 0, bottom = row-1;
        vector<int> s;
        while(left <= right && top <= bottom) 
        {
            /*顺时针*/
            for(int i = left; i <= right; i++) s.push_back(res[top][i]);

            for(int i = top + 1; i <= bottom; i++) s.push_back(res[i][right]); 
			   
            if(top != bottom)
            {
                 for(int i = right - 1; i >= left; i--) s.push_back(res[bottom][i]);    
            }

            if(left != right)
            {
                 for(int i = bottom - 1;i >= top + 1 ; i--) s.push_back(res[i][left]);    
            }
            left++, top++, right--, bottom--;
            /*当矩阵较大,能够绕完顺时针后再逆时针绕圈时,
            以下为逆时针录入情况*/
            if(left < right && top < bottom)
            {
				for(int i = top; i <= bottom ; i++) s.push_back(res[i][left]);
	            
	            for(int i = left + 1; i <= right ; i++) s.push_back(res[right-1][i]);
	            
	            if(left != right)
	            {
	            	for(int i = bottom - 1; i >= top; i--) s.push_back(res[i][right]);
				}
				if(top != bottom)
				{
					for(int i = right - 1; i >= left + 1; i--) s.push_back(res[top][i]);
				}
				left++, top++, right--, bottom--;
			}
        }
        for(int i = 0; i < s.size(); i++)
        {
            if (i == s.size() - 1)
                cout << s[i] << endl;
            else
                cout << s[i] << ' ';
        }
        
    }
    return 0;
}

5

二元一次多项式求幂

total submissions: 1728times

passed: 438times

passing rate: 25.35%

memory limit: 104857600(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

题目描述

给定一个常数项为0的二元一次多项式,求该多项式的幂。

设未知数为x,y,输入为x和y的整数系数a,b以及整数幂n,输出形如以下样式

求幂运算的结果,按照x的幂降序排列

Input Format

输入未知数整数系数 a,b (-100<a,b<100),n (1<n<6)

Output Format

幂运算的结果的多项式,按照x幂降序排列  

Example

Input

 2 3 2

Output

4x^2+12xy+9y^2

说明

幂为1时不输出^1

系数为1时不输出系数,-1只输出负号。

sample inpput and output

样例1

input:

2 3 2

output:

4x^2+12xy+9y^2

#include<iostream>
#include<queue>
#include<string>
#include<string.h>
using namespace std;

//将数字的非符号部分存入字符串 
string getNum(const string& s) {
	int t = s.size();
	string str = "";
	if (s[0] == '-')
	{
		for (int i = 1; i < s.size(); i++)
		    str += s[i];
	}
	else
	{
		for (int i = 0; i < s.size(); i++)
		    str += s[i];
	}
	return str;
}

//乘法,逐位计算,将结果存入数组再转为字符串 
string multi(const string& a, const string& b) 
{
	int len1, len2;
	int isNeg = 0;
	if (((a[0] == '-' && b[0] != '-') || (a[0] != '-' && b[0] == '-')) && (a != "0" && b != "0")) isNeg = 1;
	string num1 = getNum(a);
	string num2 = getNum(b);
	len1 = num1.size();
	len2 = num2.size();

	int* res = new int[len1 + len2];
	memset(res, 0, sizeof(int) * (len1 + len2));


	for (int i = len1 - 1; i >= 0; --i) 
	{
		for (int j = len2 - 1; j >= 0; --j) {
			res[i + j + 1] += (num1[i] - '0') * (num2[j] - '0');
		}
	}
	for (int i = len1 + len2 - 1; i >= 0; --i) 
	{
		if (res[i] >= 10) {
			res[i - 1] += res[i] / 10;
			res[i] %= 10;
		}
	}
	string ans = "";
	for (int i = 0; i < len1 + len2; ++i) ans += res[i] + '0';
	if (isNeg) ans = '-' + ans;
	return ans;
}

//加法 
string plusNum(const string& num1, const string& num2) 
{
	int len1 = num1.size(), len2 = num2.size();
	int len = max(len1, len2) + 1;
	int length = len;
	string ans = "";
	int* res = new int[length]; 
	memset(res, 0, sizeof(int) * length);

	while (len1 > 0 && len2 > 0) 
	{
		res[len - 1] = (num1[len1 - 1] - '0') + (num2[len2 - 1] - '0');
		len1--;
		len2--;
		len--;
	}
	while (len1 > 0) 
	{
		res[len - 1] = (num1[len1 - 1] - '0');
		len1--;
		len--;
	}
	while (len2 > 0) 
	{
		res[len - 1] = (num2[len2 - 1] - '0');
		len2--;
		len--;
	}
	for (int i = length - 1; i >= 0; --i) 
	{
		if (res[i] >= 10) 
		{
			res[i - 1] += res[i] / 10;
			res[i] %= 10;
		}
	}

	int k;
	for (k = 0; k < length; k++)
		if (res[k] != 0)break;
	if (k == length)ans = "0";
	else 
	{
		for (int i = k; i < length; i++)
			ans += res[i] + '0';
	}
	return ans;
}

//减法 
string minusNum(string& num1, string& num2) 
{
	int len1 = num1.size();
	int len2 = num2.size();
	int len;
	if (len1 >= len2) 
	{
		for (int i = 1; i <= len1 - len2; i++)
			num2 = '0' + num2;
		len = len1;
	}
	if (len2 > len1) 
	{
		for (int i = 1; i <= len2 - len1; i++)
			num1 = '0' + num1;
		len = len2;
	}

	int* num_a = new int[len];
	int* num_b = new int[len];
	for (int i = 0; i < len; ++i) 
	{
		num_a[i] = num1[i] - '0';
		num_b[i] = num2[i] - '0';
	}
	int q = 0;//记录退位 
	for (int i = len - 1; i >= 0; --i) 
	{
		num_a[i] -= q;
		if (num_a[i] < num_b[i]) {
			num_a[i] += 10;
			q = 1;
		}
		num_b[i] = num_a[i] - num_b[i];
	}
	
	int k;
	string ans = "";
	for (k = 0; k < len; k++)
		if (num_b[k] != 0)break;
	if (k == len)ans = "0";
	else 
	{
		for (int i = k; i < len; i++)
			ans += num_b[i] + '0';
	}
	return ans;
}

//判断两数相减结果是否为非负 
bool isPos(const string&str1, const string str2) 
{
	if (str1.size() > str2.size())
		return true;
	if (str1.size() == str2.size())
		return str1 > str2;
	return false;
}

//计算系数 
void powerFun(queue<string>& q, int n, const string& a, const string& b) 
{
	string t = "0";
	string s;
	string num1, num2;
	string ans;
	for (int i = 2; i <= n; i++) 
	{
		q.push(to_string(0));
		for (int j = 1; j <= i + 1; j++) 
		{
			s = q.front();
			q.pop();
			
			num1 = multi(t, b);
			num2 = multi(s, a);
			if (num1[0] != '-' && num2[0] != '-')
				ans = plusNum(num1, num2);
			else if (num1[0] == '-' && num2[0] == '-') 
			{
				ans = plusNum(getNum(num1), getNum(num2));
				ans = '-' + ans;
			}
			if (num1[0] == '-' && num2[0] != '-') 
			{
				num1 = getNum(num1);
				if (isPos(num2, num1)) 
				{
					ans = minusNum(num2, num1);
				}
				else 
				{
					ans = '-' + minusNum(num1, num2);
				}
			}
			if (num1[0] != '-' && num2[0] == '-') 
			{
				num2 = getNum(num2);
				if (isPos(num1, num2)) 
				{
					ans = minusNum(num1, num2);
				}
				else 
				{
					ans = '-' + minusNum(num2, num1);
				}
			}
			q.push(ans);
			t = s;
		}
	}
}

//表达式输出处理 
void showRes(queue<string>& q, int n) 
{
	int k = n;
	int flag = 1;
	while (!q.empty()) 
	{
		if (q.front() == "0" ) 
		{
			q.pop();
			k--;
			flag = 0;
			continue;
		}
		else if (q.front() == "1") 
		{
			if (flag != 0 && k < n)cout << '+';
			flag = 1;
		}
		else if (q.front()[0] != '-') 
		{
			if (k < n)cout << '+';
			cout << q.front();
		}
		else if (q.front() == "-1") cout << '-';
		else if (q.front()[0] == '-') cout << q.front();

		if (k == 1) cout << 'x';
		else if (k != 0) cout << "x^" << k;
		if (k == n - 1) cout << 'y';
		else if (k != n) cout << "y^" << n - k;

		q.pop();
		k--;
	}
	cout << endl;
}



int main() 
{
	int a, b, n;
	cin >> a >> b >> n;
	queue<string>q;
	string str1 = to_string(a);
	string str2 = to_string(b);
	q.push(str1);
	q.push(str2);
	powerFun(q, n, str1, str2);
	showRes(q, n);
	return 0;
}

6

linux路径

total submissions: 998times

passed: 376times

passing rate: 37.68%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

给定一个非最简的Linux文件绝对路径,将其简化为标准的Linux文件绝对路径。

在Linux文件路径中,一个英文句号 . 表示当前目录,两个连续的英文句号 .. 表示返回到上一级目录。

标准的Linux文件绝对路径具有以下特点

第一个字符为斜杠 /

两个目录名称直接有且仅有一个斜杠 /

除根目录外,路径结尾不能为斜杠 /

不会出现一个英文句号 . 或者两个连续的英文句号 ..

Input Format

输入由一行字符串组成,为非最简的Linux文件绝对路径。

Output Format

输出一行,为最简化的Linux文件绝对路径。

Example

Input

/aaa/../../bbb/ccc/..///./..

Output

/

说明

路径从根目录开始从左往右进行解析

aaa 表示进入根目录下 aaa 目录

.. 表示返回上一级目录,即返回根目录

.. 表示返回上一级目录,但当前目录为根目录,无上一级目录。故仍处于根目录。

bbb 表示进入根目录下 bbb 目录

ccc 表示进入 bbb 目录下 ccc 目录

.. 表示返回上一级目录,即返回 bbb 目录

后续若干个连续的斜杠 / 间没有目录名称,直接删除

. 表示当期文件夹,故仍处于 bbb 目录

.. 表示返回上一级目录,即返回根目录

根目录用斜杠 / 表示,故输出斜杠 /

sample inpput and output

样例1

input:

/aaa/../../bbb/ccc/..///./..

output:

/

样例2

input:

/home/

output:

/home

#include<iostream>
#include<cmath>
#include<stack>
#include<cstring>
#include<string>
#include<iomanip>
using namespace std;

int main()
{
	stack<string> str;
	string a;
	cin>>a;
	int len = a.length();
	int j;
	for(int i=0;i<len;i++)
	{
		if(a[i]=='/')
		{
			continue;
		}
		else
		{
			if(a[i]=='.'&&(i==len-1||a[i+1]!='.'))
			{
				continue;
			}
			if(a[i]=='.'&&i<len-1&&a[i+1]=='.')
			{
				if(str.empty())
				{
					i++;
					continue;
				}
				else
				{
					str.pop();
					i++;
					continue;
				}
			}
			string b = "";
			if(i==len-1)
			{
				b = b + a[i];
				str.push(b);
				continue;
			}
			else
			{
				b = b + a[i];
				j=i+1;
				while(j<len&&a[j]!='/'&&a[j]!='.')
				{
					b = b + a[j];
					j++;
				}
				i=j;
				str.push(b);
				continue;
			}
		}
	}
	if(str.empty())
	{
		cout<<'/';
	}
	else
	{
		cout<<'/';
		stack<string> str1;
		while(!str.empty())
		{
			str1.push(str.top());
			str.pop();
		}
		while(!str1.empty())
		{
			if(str1.size()==1)
			{
				cout<<str1.top();
				str1.pop();
				continue;
			}
			cout<<str1.top()<<'/';
			str1.pop();
		}
	}
	return 0;
} 

7

DS-表达式求值

total submissions: 3004times

passed: 624times

passing rate: 20.77%

memory limit: 104857600(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

设计一个表达式求值的程序。该程序必须可以接受包含(,),+,-,*,/,%和^(求幂)的中缀表达式,并求出结果。如果表达式正确,则输出表达式的值,如果表达式非法,则输出错误信息。
注意2^2^3转为后缀应为223^^

操作数均转为double运算。

幂运算可以直接使用pow(a,b)

%,操作数转为Int再进行计算。

输入要求:

多个表达式,每个表达式占一行。

输出要求:

对每个表达式,如果为正确表达式则输出结果(精确到小数点后两位),如果为错误表达式则输出“ERROR IN INFIX NOTATION”.

sample inpput and output

样例1

input:

(2-4)^3

output:

-8.00

样例2

input:

(3*5*(4+8)%2)

output:

0.00

样例3

input:

1+2(

output:

ERROR IN INFIX NOTATION

#include<iostream>
#include<cmath>
#include<iomanip>
#include<stack>
#include<string>
#include<cstring>
using namespace std;
int get_level(char x)
{
	if (x == '+' || x == '-')
		return 1;
	if (x == '*' || x == '/' || x == '%')
		return 2;
	if (x == '^')
		return 3;
	if (x == '(' || x == ')')
		return 4;
}


bool isnumber(char x)
{
	if (x >= '0' && x <= '9')
		return 1;
	else
		return 0;
}

bool isnumber2(char x)
{
	if (x == '+' || x == '-' || x == '*' || x == '/' || x == '^' || x == '%' || x == ')' || x == '(' || x == '.')
		return false;
	else
		return true;
}

double count(double x, double y, double z)
{
	if (z == '+')
		return (x + y);
	else if (z == '-')
		return (x - y);
	else if (z == '*')
		return (x * y);
	else if (z == '/')
	{
		if (y == 0)
		{
			cout << "ERROR IN INFIX NOTATION";
			exit(1);
		}
		return (x / y);
	}
	else if (z == '%')
		return double((int)x % (int)y);
	else
	{
		double m = double(x);
		double n = double(y);
		return (pow(m, n));
	}
}
int main()
{
	int get_level(char x);
	bool isnumber(char x);
	bool isnumber2(char x);
	double count(double x, double y, double z);
	double e = 0;
	string str;
	cin >> str;
	int  i, j;
	int length;
	double temp, temp_, temp_new;
	length = str.size();
	float str_[length];
	stack <char> stack1;
	stack <int> stack1_level;
	for (i = 0, j = 0; i < length;)
	{
		if (isnumber2(str[i]))
		{
			if (i > 0 && isnumber(str[i - 1]) && e == 0)
			{
				str_[j - 1] = (str_[j - 1]) * 10 + str[i] - '0';
				i++;
				continue;
			}
			if (e != 0)
			{
				str_[j - 1] = str_[j - 1] + (str[i] - '0') * pow(10, -e);
				i++;
				e = e + 1;
				continue;
			}
			str_[j] = str[i] - '0';
			j++;
			i++;
			continue;
		}
		else
		{
			if (str[i] == '.')
			{
				e = 1;
				i++;
				continue;
			}
			e = 0;
			if (str[i] == ')')
			{
				if (stack1.size() == 0)
				{
					cout << "ERROR IN INFIX NOTATION";
					return 0;
				}
				else
				{
					while (stack1.size() != 0 && stack1.top() != '(')
					{
						str_[j] = stack1.top();
						j++;
						stack1.pop();
						stack1_level.pop();
					}
					if (stack1.size() == 0)
					{
						cout << "ERROR IN INFIX NOTATION";
						return 0;
					}
					if (stack1.top() == '(')
					{
						stack1.pop();
						stack1_level.pop();
						i++;
						continue;
					}
				}
			}
			if (stack1.size() == 0)
			{
				stack1.push(str[i]);
				stack1_level.push(get_level(str[i]));
				i++;
				continue;
			}
			if (stack1.top() == '(')
			{
				stack1.push(str[i]);
				stack1_level.push(get_level(str[i]));
				i++;
				continue;
			}
			if (stack1_level.top() == '(')
			{
				stack1.push(str[i]);
				stack1_level.push(get_level(str[i]));
				i++;
				continue;
			}
			if (get_level(str[i]) > stack1_level.top())
			{
				stack1.push(str[i]);
				stack1_level.push(get_level(str[i]));
				i++;
				continue;
			}
			else
			{
				if (str[i] == '^' && stack1.top() == '^')
				{
					stack1.push(str[i]);
					stack1_level.push(get_level(str[i]));
					i++;
					continue;
				}
				str_[j] = stack1.top();
				stack1.pop();
				stack1_level.pop();
				j++;
				continue;
			}
		}
	}
	while (stack1.size() != 0)
	{
		str_[j] = stack1.top();
		j++;
		stack1.pop();
		stack1_level.pop();
	}
	str_[j] = '\0';
	length = j;
	for (i = 0; i < length; i++)
	{
		if (str_[i] == '(')
		{
			cout << "ERROR IN INFIX NOTATION";
			return 0;
		}
		else
			continue;
	}
	if (length == 0)
	{
		cout << "ERROR IN INFIX NOTATION";
		return 0;
	}
	stack <double> stack1_num;
	for (i = 0; i < length;)
	{
		if (length == 1)
		{
			if (isnumber2(str_[i]))
			{
				cout << fixed << setprecision(2) << str_[i];
				return 0;
			}
			else
			{
				cout << "ERROR IN INFIX NOTATION";
				return 0;
			}
		}
		if (isnumber2(str_[i]))
		{
			stack1_num.push(double(str_[i]));
			i++;
		}
		else
		{
			if (stack1_num.size() >= 2)
			{
				temp = stack1_num.top();
				stack1_num.pop();
				temp_ = stack1_num.top();
				stack1_num.pop();
				temp_new = count(temp_, temp, str_[i]);
				stack1_num.push(temp_new);
				i++;
			}
			else
			{
				cout << "ERROR IN INFIX NOTATION";
				return 0;
			}
		}
	}
	cout << fixed << setprecision(2) << double(stack1_num.top());
	return 0;
}

8

二元一次多项式的幂(大整数)

total submissions: 1018times

passed: 367times

passing rate: 36.05%

memory limit: 41943040(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

题目描述

给定一个常数项为0的二元一次多项式,求该多项式的幂。

设未知数为x,y,输入为x和y的整数系数a,b以及整数幂n,输出形如以下样式

求幂运算的结果,按照x的幂降序排列

Input Format

输入未知数整数系数 a,b (-1000<a,b<1000),n (2<n<20)

Output Format

幂运算的结果的多项式,按照x幂降序排列  

Example

Input

99 100 15  

Output

860058354641288524893953951499x^15+13031187191534674619605362901500x^14y+92139707414891638724482363950000x^13y^2+403305116630838822699754455000000x^12y^3+1222136717063147947575013500000000x^11y^4+2715859371251439883500030000000000x^10y^5+4572153823655622699495000000000000x^9y^6+5937862108643665843500000000000000x^8y^7+5997840513781480650000000000000000x^7y^8+4712108147752005000000000000000000x^6y^9+2855823119849700000000000000000000x^5y^10+1311213553650000000000000000000000x^4y^11+441486045000000000000000000000000x^3y^12+102910500000000000000000000000000x^2y^13+14850000000000000000000000000000xy^14+1000000000000000000000000000000y^15

说明

幂为1时不输出^1

系数为1时不输出系数,-1只输出负号。

sample inpput and output

样例1

input:

99 100 15

output:

860058354641288524893953951499x^15+13031187191534674619605362901500x^14y+92139707414891638724482363950000x^13y^2+403305116630838822699754455000000x^12y^3+1222136717063147947575013500000000x^11y^4+2715859371251439883500030000000000x^10y^5+4572153823655622699495000000000000x^9y^6+5937862108643665843500000000000000x^8y^7+5997840513781480650000000000000000x^7y^8+4712108147752005000000000000000000x^6y^9+2855823119849700000000000000000000x^5y^10+1311213553650000000000000000000000x^4y^11+441486045000000000000000000000000x^3y^12+102910500000000000000000000000000x^2y^13+14850000000000000000000000000000xy^14+1000000000000000000000000000000y^15

#include<iostream>
#include<queue>
#include<string>
#include<string.h>
using namespace std;

//将数字的非符号部分存入字符串 
string getNum(const string& s) {
	int t = s.size();
	string str = "";
	if (s[0] == '-')
	{
		for (int i = 1; i < t; i++)
		    str += s[i];
	}
	else
	{
		for (int i = 0; i < t; i++)
		    str += s[i];
	}
	return str;
}

//乘法,逐位计算,将结果存入数组再转为字符串 
string multi(const string& a, const string& b) 
{
	int len1, len2;
	int isNeg = 0;
	if (((a[0] == '-' && b[0] != '-') || (a[0] != '-' && b[0] == '-')) && (a != "0" && b != "0")) isNeg = 1;
	string num1 = getNum(a);
	string num2 = getNum(b);
	len1 = num1.size();
	len2 = num2.size();

	int* res = new int[len1 + len2];
	memset(res, 0, sizeof(int) * (len1 + len2));


	for (int i = len1 - 1; i >= 0; --i) 
	{
		for (int j = len2 - 1; j >= 0; --j) {
			res[i + j + 1] += (num1[i] - '0') * (num2[j] - '0');
		}
	}
	for (int i = len1 + len2 - 1; i >= 0; --i) 
	{
		if (res[i] >= 10) {
			res[i - 1] += res[i] / 10;
			res[i] %= 10;
		}
	}
	string ans = "";
	for (int i = 0; i < len1 + len2; ++i) ans += res[i] + '0';
	if (isNeg) ans = '-' + ans;
	return ans;
}

//加法 
string plusNum(const string& num1, const string& num2) 
{
	int len1 = num1.size(), len2 = num2.size();
	int len = max(len1, len2) + 1;
	int length = len;
	string ans = "";
	int* res = new int[length]; 
	memset(res, 0, sizeof(int) * length);

	while (len1 > 0 && len2 > 0) 
	{
		res[len - 1] = (num1[len1 - 1] - '0') + (num2[len2 - 1] - '0');
		len1--;
		len2--;
		len--;
	}
	while (len1 > 0) 
	{
		res[len - 1] = (num1[len1 - 1] - '0');
		len1--;
		len--;
	}
	while (len2 > 0) 
	{
		res[len - 1] = (num2[len2 - 1] - '0');
		len2--;
		len--;
	}
	for (int i = length - 1; i >= 0; --i) 
	{
		if (res[i] >= 10) 
		{
			res[i - 1] += res[i] / 10;
			res[i] %= 10;
		}
	}

	int k;
	for (k = 0; k < length; k++)
		if (res[k] != 0)break;
	if (k == length)ans = "0";
	else 
	{
		for (int i = k; i < length; i++)
			ans += res[i] + '0';
	}
	return ans;
}

//减法 
string minusNum(string& num1, string& num2) 
{
	int len1 = num1.size();
	int len2 = num2.size();
	int len;
	if (len1 >= len2) 
	{
		for (int i = 1; i <= len1 - len2; i++)
			num2 = '0' + num2;
		len = len1;
	}
	if (len2 > len1) 
	{
		for (int i = 1; i <= len2 - len1; i++)
			num1 = '0' + num1;
		len = len2;
	}

	int* num_a = new int[len];
	int* num_b = new int[len];
	for (int i = 0; i < len; ++i) 
	{
		num_a[i] = num1[i] - '0';
		num_b[i] = num2[i] - '0';
	}
	int q = 0;//记录退位 
	for (int i = len - 1; i >= 0; --i) 
	{
		num_a[i] -= q;
		if (num_a[i] < num_b[i]) {
			num_a[i] += 10;
			q = 1;
		}
		num_b[i] = num_a[i] - num_b[i];
	}
	
	int k;
	string ans = "";
	for (k = 0; k < len; k++)
		if (num_b[k] != 0)break;
	if (k == len)ans = "0";
	else 
	{
		for (int i = k; i < len; i++)
			ans += num_b[i] + '0';
	}
	return ans;
}

//判断两数相减结果是否为非负 
bool isPos(const string&str1, const string str2) 
{
	if (str1.size() > str2.size())
		return true;
	if (str1.size() == str2.size())
		return str1 > str2;
	return false;
}

//计算系数 
void powerFun(queue<string>& q, int n, const string& a, const string& b) 
{
	string t = "0";
	string s;
	string num1, num2;
	string ans;
	for (int i = 2; i <= n; i++) 
	{
		q.push(to_string(0));
		for (int j = 1; j <= i + 1; j++) 
		{
			s = q.front();
			q.pop();
			
			num1 = multi(t, b);
			num2 = multi(s, a);
			if (num1[0] != '-' && num2[0] != '-')
				ans = plusNum(num1, num2);
			else if (num1[0] == '-' && num2[0] == '-') 
			{
				ans = plusNum(getNum(num1), getNum(num2));
				ans = '-' + ans;
			}
			if (num1[0] == '-' && num2[0] != '-') 
			{
				num1 = getNum(num1);
				if (isPos(num2, num1)) 
				{
					ans = minusNum(num2, num1);
				}
				else 
				{
					ans = '-' + minusNum(num1, num2);
				}
			}
			if (num1[0] != '-' && num2[0] == '-') 
			{
				num2 = getNum(num2);
				if (isPos(num1, num2)) 
				{
					ans = minusNum(num1, num2);
				}
				else 
				{
					ans = '-' + minusNum(num2, num1);
				}
			}
			q.push(ans);
			t = s;
		}
	}
}

//表达式输出处理 
void showRes(queue<string>& q, int n) 
{
	int k = n;
	int flag = 1;
	while (!q.empty()) 
	{
		if (q.front() == "0" ) 
		{
			q.pop();
			k--;
			flag = 0;
			continue;
		}
		else if (q.front() == "1") 
		{
			if (flag != 0 && k < n)cout << '+';
			flag = 1;
		}
		else if (q.front()[0] != '-') 
		{
			if (k < n)cout << '+';
			cout << q.front();
		}
		else if (q.front() == "-1") cout << '-';
		else if (q.front()[0] == '-') cout << q.front();

		if (k == 1) cout << 'x';
		else if (k != 0) cout << "x^" << k;
		if (k == n - 1) cout << 'y';
		else if (k != n) cout << "y^" << n - k;

		q.pop();
		k--;
	}
	cout << endl;
}



int main() 
{
	int a, b, n;
	cin >> a >> b >> n;
	queue<string>q;
	string str1 = to_string(a);
	string str2 = to_string(b);
	q.push(str1);
	q.push(str2);
	powerFun(q, n, str1, str2);
	showRes(q, n);
	return 0;
}

9

二叉树遍历及二叉树高度

total submissions: 647times

passed: 432times

passing rate: 66.77%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

给出一棵二叉树的先序遍历和中序遍历序列,计算该二叉树的高度。其中,二叉树的先序和中序遍历序列为不包含重复英文字母(区别大小写)的字符串。

Input Format

二叉树结点的总个数n<=50

然后输入先序和中序遍历序列,两个序列长度均为n。  

Output Format

二叉树高度(整数) ,叶子结点高度为1 

Example

Input

9

ABDGHCEIF
GDHBAEICF

Output

4

sample inpput and output

样例1

input:

9
ABDGHCEIF
GDHBAEICF

output:

4

#include<iostream>
#include<cstring>
using namespace std;

int calculate(char* xian,char* zhong,int n)             //求二叉树的高度
{   	if(n == 0)  { return 0;}                  //若没有结点,为空树;但实际上这个步骤可以省略了,因为输入时限定不能输入0      
	int i;    
 	for(i = 0; i < n; i++)    
 	{  if(zhong[i] == xian[0])                //找到根结点在中序的位置        
  		{break;}    
 	}
 	/*之后根据先序和中序的特点,我们就可以隔开分治了
	  在先序序列中,下标1~i是该根节点左树的范围
	  在中序序列中,i+1到之后的n-i-1是右树范围
	*/
        int left = calculate(xian+1,zhong,i);           //左子树的深度,使用递归    
 	int right = calculate(xian+i+1,zhong+i+1,n-i-1);//右子树的深度,使用递归
 	return max(left,right)+1;                 //返回左右子树深度的较大值中的较大值+根结点的1次
}
int main()
{ 	int n;    
 	while(cin>>n&&n)    
 	{ 
        	char xian[n+1],zhong[n+1];        //先序数组和中序数组    
  		cin >> xian >> zhong;    	  //输入相应的字符串
  		cout << calculate(xian,zhong,n) << endl;//输出答案
  		memset(xian,' ',sizeof(xian));    //清空数组,准备下一次接收
  		memset(zhong,' ',sizeof(zhong));
 	}    
	return 0;
}

10

村庄是否联通

total submissions: 1038times

passed: 423times

passing rate: 40.75%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

村庄中存在一些路,根据输入的相邻村庄的路,判断某两个村庄是否能够联通。n个村庄使用0到n-1的不同整数标识。路使用取值范围【0,n-1】的整数对表示。例如 3 5,代表村庄3和5之间有一条路。

Input Format

村庄个数 n, 0<n<=20

路的条数 m,0<m<=50

m条路,即为2m个范围在【0,n-1】的整数   

需要判断是否相连的村庄对数 p 0<p<=10

需要判断是否相连的p对村庄,即为2p个范围在【0,n-1】的整数。

Output Format

能够连通输出

true

,不可连通输出

false

Example

Input

5

4

0 4

2 4

0 2

1 3

2

3 4

2 4

Output

false

true

sample inpput and output

样例1

input:

5
4
0 4
2 4
0 2
1 3
2
3 4
2 4

output:

false
true

#include<iostream>
using namespace std;

//也可以用类定义,n,e, 作为类的成员变量
//查找过程中,循环,没有做优化
//查找中,路径压缩,祖父节点
int find(int key, int* par) {
 int tempindex = key;
 //当前值不等于他的根,就继续向上回溯,直到当前值与他的索引一致
 while (par[tempindex] != tempindex) {
  tempindex = par[tempindex];
  par[tempindex] = par[par[tempindex]];//祖父节点
 }
 return tempindex;//找的是父节点
}
//void-也可以加一个返回值,int or bool , 集合是否合并
bool unionset(int v1, int v2, int* par, int* rank) {
 int r1 = find(v1, par);
 int r2 = find(v2, par);
 //如果根相同,不合并,否则- 快速合并
 if (r1 == r2)return false;
 else 
 {
  //quick union
  //par[v2]=v1;//随便选一个作为根节点
  //base rank
  //重复代码可优化,简洁
  if (rank[r1] > rank[r2]) {
   par[r2] = r1;//rank不需要更新
  }
  else if (rank[r1] < rank[r2]) {
   par[r1] = r2;
  }
  else {
   par[r2] = r1;
   rank[r1]++;
  }
 }
 return true;
}
int main() {
 int n, e;
 cin >> n >> e;
 int* parent = new int[n];
 for (int i = 0; i < n; i++) {
  parent[i] = i;
 }
 int* rank = new int[n];
 for (int i = 0; i < n; i++) {
  rank[i] = 1;
 }//和memreset 一样,都是用循环做初始化

 //插入边,其实就是一个合并的过程
 for (int i = 0; i < e; i++) {
  int v1, v2;
  cin >> v1 >> v2;
  unionset(v1, v2, parent, rank);
 }
 int t;
 cin >> t;
 for (int i = 0; i < t; i++) {
  int v1, v2;
  cin >> v1 >> v2;
  if (find(v1, parent) == find(v2, parent)) {
   cout << "true" << endl;
  }
  else {
   cout << "false" << endl;
  }
 }

 return 0;
}

11

判断是否为堆-堆整理

total submissions: 730times

passed: 331times

passing rate: 45.34%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

请判断输入的整数序列是否为堆。

如果为最大堆,请输出“max ”以及整理后的最小堆,整数序列数字之间有空格,最后无空格。

如果为最小堆,请输出“min ” 以及整理后的最大堆,整数序列数字之间有空格,最后无空格。

如果不为堆,请输出整理后的最大堆,整数序列数字之间有空格,最后无空格。

如果既是最大堆也是最小堆,请只输出“max min ”

Input Format

先输入整数序列个数n 0<n<1000

然后输入n个整数序列,整数取值范围【-100000,100000】

Output Format

最大堆或最小堆序列

Example

Input

10
-8 8 -9 10 -2 1 -6 -9 7 2 

Output

10 8 1 7 2 -9 -6 -9 -8 -2

Input

10
10 8 1 7 2 -9 -6 -9 -8 -2

Output

max -9 -9 -6 -8 -2 1 10 7 8 2

Input

 10
-9 -9 -6 -8 -2 1 10 7 8 2

Output

min 10 8 1 7 2 -9 -6 -9 -8 -2

Input

 3
1 1 1

Output

max min 

注意:序列最后无空格,max和min后面均有空格。

如案例,定义以下实现约束:两个相等子节点情况下,整理过程中,父节点下沉时,选择右沉。

10

10 8 1 7 2 -9 -6 -9 -8 -2

 两个相等子节点情况下,整理过程中,父节点下沉时,选择右沉。

sample inpput and output

样例1

input:

10
-9 -9 -6 -8 -2 1 10 7 8 2

output:

min 10 8 1 7 2 -9 -6 -9 -8 -2

样例2

input:

3
1 1 1

output:

max min 

样例3

input:

10
10 8 1 7 2 -9 -6 -9 -8 -2

output:

max -9 -9 -6 -8 -2 1 10 7 8 2

样例4

input:

10
-8 8 -9 10 -2 1 -6 -9 7 2 

output:

10 8 1 7 2 -9 -6 -9 -8 -2

#include<iostream>
using namespace std;
int flag = 0; 
void IsHeap(int num[], int n) {
	bool isMax = true, isMin = true;//初始默认为堆 
	int lChild, rChild;
	for (int i = 1; i <= n; ++i) 
	{
		lChild = i * 2;
		rChild = i * 2 + 1;
		if (rChild <= n) 
		{
			if (num[i] == num[lChild] && num[i] == num[rChild])continue;//结点与孩子相等,可以是最大堆也可以是最小堆。 
			else if (num[i] <= num[lChild] && num[i] <= num[rChild])//结点的左右孩子都不比它小,故不是最大堆。 
				isMax = false;
			else if (num[i] >= num[lChild] && num[i] >= num[rChild])//结点的左右孩子都不比它大,故不是最小堆。 
				isMin = false;
			else
			{
				isMax = isMin = false;
				break;
			}
		}
		else if (lChild <= n) 
		{
			if (num[i] == num[lChild])continue;
			else if (num[i] < num[lChild])
				isMax = false;
			else if (num[i] > num[lChild])
				isMin = false;
			else 
			{
				isMax = isMin = false;
				break;
			}
		}
	}
	//四种结果 
	if (isMax == true) 
	{
		if (isMin == false)flag = 1;
		if (isMin == true)flag = 3;
	}
	else 
	{
		if (isMin == true)flag = 2;
		if (isMin == false)flag = 4;
	}
}
void BuildMaxHeap(int num[], int n) //生成最大堆 
{
	for (int i = n / 2; i >= 1; --i) 
	{
		int t = num[i];//结点 
		int c = i * 2;//左孩子 
		while (c <= n) 
		{
			if (c < n && num[c] <= num[c + 1])
				c++;
			if (t < num[c]) //结点小于左孩子 
			{
				num[c / 2] = num[c];//将左孩子的值赋给结点 
				c *= 2;//出while循环 
			}
			else break;//出while循环 
		}
		num[c / 2] = t;//将原结点的值赋给左孩子 
	}
}

void BuildMinHeap(int num[], int n) //生成最小堆 
{
	for (int i = n / 2; i >= 1; --i) 
	{
		int t = num[i];
		int c = i * 2;
		while (c <= n) 
		{
			if (c < n && num[c] >= num[c + 1])
				c++;
			if (t > num[c]) 
			{
				num[c / 2] = num[c];
				c *= 2;
			}
			else break;
		}
		num[c / 2] = t;
	}
}
void BuildHeap(int num[], int n) 
{

	if (flag == 1) 
	{
		cout << "max ";
		BuildMinHeap(num, n);
	}
	if (flag == 2) 
	{
		cout << "min ";
		BuildMaxHeap(num, n);
	}
	if (flag == 3) 
	{
		cout << "max min" << endl;
		return;
	}
	if (flag == 4) 
	{
		BuildMaxHeap(num, n);
	}
	for (int i = 1; i <= n; ++i) 
	{
		if (i == n)cout << num[i];
		else cout << num[i] << " ";
	}
}
int main() {
	int n, num1[1001];
	cin >> n;
	for (int i = 1; i <= n; ++i)
		cin >> num1[i];
	IsHeap(num1, n);
	BuildHeap(num1, n);
	return 0;
}

12

完全二叉树的先序遍历

total submissions: 783times

passed: 414times

passing rate: 52.87%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

给出一棵完全二叉树的先序遍历,输出其后序遍历。结点均为不重复的单个英文字母,区分大小写。结点总数小于52。

Input Format

输入先序字符串

Output Format

后序遍历字符串

Example

Input

 

ABDGHCEIF

Output

GHDCBIFEA

sample inpput and output

样例1

input:

ABDGHCEIF

output:

GHDCBIFEA

样例2

input:

a

output:

a

#include<iostream>
#include<string>
using namespace std;
int pos;
void pretrav(string & pct,char*ct,int r,int len){
if (r < len) {
	ct[r] = pct[pos++];
	pretrav(pct, ct, r * 2 + 1, len);
	pretrav(pct, ct, r * 2 + 2, len);
    }
}
void posttrav(char* ct, int r, int len) {
	if (r < len) {
		posttrav(ct, r * 2 + 1, len);
		posttrav(ct, r * 2 + 2, len);
		cout << ct[r];
	}
}
int main() {
	string input;
	cin >> input;
	char* ct = new char[input.size()];
	pretrav(input, ct, 0, input.size());
	posttrav(ct, 0, input.size());
	delete ct;
}

13

求整数最大间隔-性能

total submissions: 1388times

passed: 488times

passing rate: 35.16%

memory limit: 524288000(BYTE)

time limit: 1500(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

题目描述

请输出数字序列的最大间隔。

请使用以下伪随机数生成函数 rand32 () 生成伪随机数

int  seed  ;
int rand(){ return((( seed   =  seed   * 214013L + 2531011L) >> 16) & 0x7fff); }
int rand32(){
return ((rand() << 16) + (rand() << 1) + rand() % 2);
}

Input Format

2个整数,n seed 其中 2<n<=20000000,seed为随机数种子。

Output Format

整数序列的最大间隔

Example

Input

2000000
1

Output

15737

注意:O(nlogn)以上的时间复杂度至少会有一个案例超时。

sample inpput and output

样例1

input:

1959000 4910

output:

16709

#include<iostream>
#include<string.h>
using namespace std;

int n,seed;
int randI() {
	return(((seed = seed * 214013L + 2531011L) >> 16) & 0x7fff);
}
int rand32() {
	return ((randI() << 16) + (randI() << 1) + randI() % 2);
}
int maxGap(int arr[]) {
	int minN = arr[0], maxN = arr[0]; 
	//遍历找到数组中最大值最小值。 
	for (int i = 0; i < n; ++i) 
	{
		if (arr[i] > maxN)maxN = arr[i];
		if (arr[i] < minN)minN = arr[i];
	}
	if (maxN == minN)return 0;
    //构造n+1个桶。 
	bool* hasNum = new bool[n + 1];
	memset(hasNum, 0, sizeof(bool) * (n + 1));
	int* mins = new int[n + 1];
	int* maxs = new int[n + 1];
	//遍历数组 找到每个桶中max min。 
	for (int i = 0; i < n; ++i) 
	{
		//double gap = double(maxN - minN + 1) / (n + 1);
		double gap = double(maxN - minN) / (n - 1);
		int index = int((arr[i] - minN) / gap); //几号桶。  
		if (!hasNum[index])  
		{
			mins[index] = maxs[index] = arr[i];
			hasNum[index] = true;
		}
		else 
		{
			mins[index] = min(arr[i], mins[index]);
			maxs[index] = max(arr[i], maxs[index]);
		}
	}

	int maxGap = 0;
	int lastMax = maxs[0];
	for (int i = 1; i <= n; i++) 
	{
		if (hasNum[i]) //不是空桶。 
		{
			maxGap = max(maxGap, (mins[i] - lastMax));
			//cout << mins[i] << ' ' << lastMax << endl;
			lastMax = maxs[i];
		}
	}

	delete[]hasNum;
	delete[]maxs;
	delete[]mins;
	return maxGap;
}
int main() {
	cin >> n >> seed;
	int* arr = new int[n];
	for (int i = 0; i < n; ++i)
		arr[i] = rand32();
	cout << maxGap(arr) << endl;
	delete[]arr;
	return 0;
}

14

创建AVL树并判断是否为完全二叉树

total submissions: 1049times

passed: 433times

passing rate: 41.28%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

在AVL树中,任何节点的两个子树的高度最多相差1;如果它们高度相差不止1,则需要重新平衡以恢复这种属性。

现在给定一个插入序列, 一个一个地将键值插入初始为空的AVL树中,输出得到的AVL树的层次顺序遍历序列,并判断它是否是一个完全二叉树。

输入格式:

第一行包含一个正整数N(<= 20)。然后在下一行给出N个不同的整数键。所有数字都用空格隔开。

输出格式:

第一行打印得到的AVL树的层次顺序遍历序列。所有数字都必须用空格隔开,并且行尾必须没有多余的空格。然后在下一行中,如果树为完全二叉树,则打印“Yes”;如果不是,则打印“No”。

样例输入1:

5
88 70 61 63 65 

样例输出1:

70 63 88 61 65

Yes

样例输入2:

10
62 88 58 47 35 73 51 99 37 93 

样例输出2:

62 47 88 35 58 73 99 37 51 93
No  

sample inpput and output

样例1

input:

5
88 70 61 63 65

output:

70 63 88 61 65
Yes

样例2

input:

10
62 88 58 47 35 73 51 99 37 93

output:

62 47 88 35 58 73 99 37 51 93
No

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct Node{
	int data,hi,id;
	struct Node *Left,*Right;
};
typedef struct Node *Tree;
int MAX(int x,int  y)
{
	return x>y?x:y;
}
int Height(Tree T)
{
	if(T==NULL) return -1;
	else return T->hi;
}
Tree LeftRotate(Tree T)
{
	Tree p=T->Left;
	T->Left=p->Right;
	p->Right=T;
	T->hi=MAX(Height(T->Left),Height(T->Right))+1;
	p->hi=MAX(Height(p->Left),T->hi)+1;
	return p;
}
Tree RightRotate(Tree T)
{
	Tree p=T->Right;
	T->Right=p->Left;
	p->Left=T;
	T->hi=MAX(Height(T->Left),Height(T->Right))+1;
	p->hi=MAX(Height(p->Right),T->hi)+1;
	return p;
}
Tree LeftRightRotate(Tree T)
{
	T->Left=RightRotate(T->Left);
	return LeftRotate(T);
}
Tree RightLeftRotate(Tree T)
{
	T->Right=LeftRotate(T->Right);
	return RightRotate(T);
}
Tree Insert(int x,Tree T)
{
	if(T==NULL){
		T=new Node;
		T->data=x;
		T->Left=NULL;
		T->Right=NULL;
		T->hi=0;
	}
	else if(x<T->data){
		T->Left=Insert(x,T->Left);
		if(Height(T->Left)-Height(T->Right)==2){
			if(x<T->Left->data) T=LeftRotate(T);
			else T=LeftRightRotate(T);
		}
	}
	else if(x>T->data){
		T->Right=Insert(x,T->Right);
		if(Height(T->Right)-Height(T->Left)==2){
			if(x>T->Right->data) T=RightRotate(T);
			else T=RightLeftRotate(T);
		}
	}
	T->hi=MAX(Height(T->Left),Height(T->Right))+1;
	return T;
}
vector <int> ans,vc;
void bfs(Tree T)
{
	Tree tmp;
	T->id=1;
	ans.clear();
	vc.clear();
	queue <Tree> q;
	q.push(T);
	while(!q.empty()){
		tmp=q.front();q.pop();
		ans.push_back(tmp->data);
		vc.push_back(tmp->id);
		if(tmp->Left!=NULL){
			tmp->Left->id=tmp->id*2;
			q.push(tmp->Left);
		}
		if(tmp->Right!=NULL){
			tmp->Right->id=tmp->id*2+1;
			q.push(tmp->Right);
		}
	}
}
int main(void)
{
	int n,i,x;
	Tree T=NULL;
	cin>>n;
	for(i=0;i<n;i++){
		cin>>x;
		T=Insert(x,T);
	}
	bfs(T);
	int fg=0;
	for(i=0,x=ans.size();i<x;i++){
		if(i){
			cout<<" ";
			if(vc[i]-vc[i-1]!=1) fg=1;
		}
		cout<<ans[i];
	}
	cout<<endl;
	if(fg==0) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
	return 0;
}

15

创建RB树

total submissions: 1175times

passed: 348times

passing rate: 29.62%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

RB(红黑)树除了是一个二叉搜索树之外,还满足下面规则:

    1)每个结点要么是红的,要么是黑的。

    2)根结点是黑的。

    3)每个叶结点,即空结点是黑的。

    4)如果一个结点是红的,那么它的俩个儿子都是黑的。

    5)对每个结点,从该结点到其子孙结点的所有路径上包含相同数目的黑结点。

在给定插入序列的情况下,创建RB树,并输出最大值、最小值。

输入格式:

对于每种情况,第一行包含一个正整数N(<=20)。后边为N个不同的整数值,每个整数值以空格隔开。

第二行为要删除的节点个数M,后边为M个不同的整数值,以空格隔开。

输出格式:

第一行为RB树的前序遍历序列,以空格隔开,其中节点值后使用(B)和(R)表示节点的颜色;

第二行为RB树的最大值,最小值,以空格隔开;

第三行为删除M个节点之后的RB树的前序遍历序列,以空格隔开,若树为空,则输出Null;

样例输入1:

13 1 45 34 98 9 4 35 23 36 37 90 85 80
3 85 27 9

样例输出1:

34(B) 4(B) 1(B) 9(B) 23(R) 45(B) 36(B) 35(R) 37(R) 90(R) 85(B) 80(R) 98(B) 
1 98
34(B) 4(B) 1(B) 23(B) 45(B) 36(B) 35(R) 37(R) 90(R) 80(B) 98(B) 

样例输入2:

3 18 2 7
0

样例输出2:

7(B) 2(R) 18(R) 
2 18
7(B) 2(R) 18(R) 

注意:遍历输出最后一个结点有空格。删除带有双子结点时,找直接后继。

sample inpput and output

样例1

input:

13 1 45 34 98 9 4 35 23 36 37 90 85 80
3 85 27 9

output:

34(B) 4(B) 1(B) 9(B) 23(R) 45(B) 36(B) 35(R) 37(R) 90(R) 85(B) 80(R) 98(B) 
1 98
34(B) 4(B) 1(B) 23(B) 45(B) 36(B) 35(R) 37(R) 90(R) 80(B) 98(B) 

样例2

input:

3 18 2 7
0

output:

7(B) 2(R) 18(R) 
2 18
7(B) 2(R) 18(R) 

#include<iostream>
using namespace std;

enum RBTcolor {B, R};
class TreeNode 
{
public:
	int data;
	RBTcolor color;
	TreeNode* left, * right, * parent;
	TreeNode(int _data, RBTcolor c, TreeNode* l, TreeNode* r, TreeNode* p):data(_data), color(c), left(l), right(r), parent(p) {};
};
class RBTree 
{
	private:
		TreeNode* root;
		void PreOrderNode(TreeNode* tree)const;
		void RightRotate(TreeNode* node);
		void LeftRotate(TreeNode* node);
		void InsertNode(TreeNode* node);
		void InsertFix(TreeNode* node);
		void DeleteNode(TreeNode* node);
		void DeleteFix(TreeNode* node, TreeNode* parent);
	public:
		RBTree() { root = NULL; }
		~RBTree(){}
		void Insert(int _data);
		void Delete(int _data);
		void FindMaxMin();
		void PreOrder();
};
void RBTree::Insert(int _data) 
{
	TreeNode* newNode;
	newNode = new TreeNode(_data, B, NULL, NULL, NULL);
	InsertNode(newNode);
}
void RBTree::InsertNode(TreeNode* node) 
{
	if (root == NULL) 
	{
		root = node;
		return;
	}
	TreeNode* tmp = root, * ptmp;
	while (tmp) 
	{
		ptmp = tmp;
		if (node->data < tmp->data)
			tmp = tmp->left;
		else
			tmp = tmp->right;
	}
	if (node->data < ptmp->data)
		ptmp->left = node;
	else ptmp->right = node;
	node->parent = ptmp;
	node->color = R;
	InsertFix(node);
}
void RBTree::InsertFix(TreeNode* node) 
{
	TreeNode* parent;
	while ((parent = node->parent) && parent->color == R) 
	{
		TreeNode* gparent = node->parent->parent;
		//父节点是祖父节点的左孩子。 
		if (parent == gparent->left) 
		{
			TreeNode* uncle = gparent->right;
			//情况1:叔结点为红色。 
			if (uncle && uncle->color == R) 
			{
				uncle->color = B;
				parent->color = B;
				gparent->color = R;
				node = gparent;
				continue;
			}
            //情况2:叔结点为黑色,插入节点为父节点的右孩子。 
			if (node == parent->right) 
			{
				LeftRotate(parent);
				swap(parent, node);
			}

			parent->color = B;
			gparent->color = R;
			RightRotate(gparent);
		}
		//父节点是祖父节点的右孩子。 
		if (parent == gparent->right) 
		{
			TreeNode* uncle = gparent->left;
			if (uncle && uncle->color == R) 
			{
				uncle->color = B;
				parent->color = B;
				gparent->color = R;
				node = gparent;
				continue;
			}
			if (node == parent->left) 
			{
				RightRotate(parent);
				swap(parent, node);
			}
			parent->color = B;
			gparent->color = R;
			LeftRotate(gparent);
		}
	}
	root->color = B;
}
void RBTree::RightRotate(TreeNode* node) 
{
	TreeNode* lchild = node->left;
	node->left = lchild->right;
	if (lchild->right)
		lchild->right->parent = node;
		lchild->parent = node->parent;
		if (node->parent == NULL)
		root = lchild;
		else 
		{
			if (node == node->parent->left)node->parent->left = lchild;
			else node->parent->right = lchild;
		}
		lchild->right = node;
		node->parent = lchild;
}
void RBTree::LeftRotate(TreeNode* node) 
{
	TreeNode* rchild = node->right;
	node->right = rchild->left;
	if (rchild->left)
		rchild->left->parent = node;
	rchild->parent = node->parent;
	if (node->parent == NULL)
		root = rchild;
	else 
	{
		if (node == node->parent->left)node->parent->left = rchild;
		else node->parent->right = rchild;
	}
	rchild->left = node;
	node->parent = rchild;
}
void RBTree::PreOrderNode(TreeNode* tree)const
{
	if (tree == NULL)return;
	cout << tree->data;
	if (tree->color == B)cout << "(B) ";
	else cout << "(R) ";
	PreOrderNode(tree->left);
	PreOrderNode(tree->right);
}
void RBTree::PreOrder() 
{
	if (root == NULL)cout << "Null";
	else PreOrderNode(root);
	cout << endl;
}


void RBTree::FindMaxMin() 
{
	TreeNode* tmp1 = root;
	TreeNode* tmp2 = root;
	while (tmp1->left) tmp1 = tmp1->left;
	while (tmp2->right)tmp2 = tmp2->right;
	cout << tmp1->data << ' ' << tmp2->data << endl;
}

//找到要删除的节点。 
void RBTree::Delete(int _data) 
{
	TreeNode* tmp = root;
	while (tmp) 
	{
		if (_data < tmp->data)
			tmp = tmp->left;
		else if (_data > tmp->data)
			tmp = tmp->right;
		else break;
	}
	if (tmp == NULL)return;
	DeleteNode(tmp);
}


void RBTree::DeleteNode(TreeNode* node) 
{
	RBTcolor tcolor = B;
	if (node->left && node->right) 
	{
		TreeNode* tmp = node->right;
		while (tmp->left)tmp = tmp->left;
		node->data = tmp->data;
		if (tmp->parent == node)node->right = tmp->right;
		else tmp->parent->left = tmp->right;
		if (tmp->right)tmp->right->parent = tmp->parent;
		tcolor = tmp->color;
		if (tcolor == B)DeleteFix(tmp->right, tmp->parent);
		delete tmp;
		return;
	}
	else if (node->left) 
	{
		if (node->parent == NULL) 
		{
			root = node->left;
			node->left->parent = NULL;
		}
		else 
		{
			if (node == node->parent->left)node->parent->left = node->left;
			else node->parent->right = node->left;
			if (node->left)node->left->parent = node->parent;
			tcolor = node->color;
		}
		if (tcolor == B)DeleteFix(node->left, node->parent);
		delete node;
	}
	else 
	{
		if (node->parent == NULL) 
		{
			root = node->right;
			if (node->right)node->right->parent = NULL;
		}
		else 
		{
			if (node == node->parent->left)node->parent->left = node->right;
			else node->parent->right = node->right;
			if (node->right)node->right->parent = node->parent;
			tcolor = node->color;
		}
		if (tcolor == B)DeleteFix(node->right, node->parent);
		delete node;
	}
}
void RBTree::DeleteFix(TreeNode* node, TreeNode* parent) 
{
	TreeNode* other;
	while ((!node || node->color == B) && node != root) 
	{
		if (node == parent->left) 
		{
			other = parent->right;
			if (other->color == R) 
			{
				other->color = B;
				parent->color = R;
				LeftRotate(parent);
				other = parent->right;
			}
			if ((!other->left || other->left->color == B) && (!other->right || other->right->color == B)) 
			{
				other->color = R;
				node = parent;
				parent = node->parent;
			}
			else 
			{
				if (!other->right || other->right->color == B) 
				{
					other->left->color = B;
					other->color = R;
					RightRotate(other);
					other = parent->right;
				}
				other->color = other->parent->color;
				parent->color = B;
				other->right->color = B;
				LeftRotate(parent);
				node = root;
				break;
			}
		}
		else 
		{
			other = parent->left;
			if (other->color == R) 
			{
				other->color = B;
				parent->color = R;
				RightRotate(parent);
				other = parent->left;
			}
			if ((!other->left || other->left->color == B) && (!other->right || other->right->color == B)) 
			{
				other->color = R;
				node = parent;
				parent = node->parent;
			}
			else 
			{
				if (!other->left || other->left->color == B) 
				{
					other->right->color = B;
					other->color = R;
					LeftRotate(other);
					other = parent->left;
				}
				other->color = parent->color;
				parent->color = B;
				other->left->color = B;
				RightRotate(parent);
				node = root;
				break;
			}
		}
	}
	if (node)
		node->color = B;
}

int main() 
{
	int n, m;
	int num1, * num2;
	cin >> n;
	RBTree t;
	for (int i = 0; i < n; i++) 
	{
		cin >> num1;
		t.Insert(num1);
	}
	cin >> m;
	num2 = new int[m];
	for (int i = 0; i < m; i++) 
	{
		cin >> num2[i];
	}
	t.PreOrder();
	t.FindMaxMin();
	for(int i = 0; i < m; i++)
	{
		t.Delete(num2[i]);
	}
	t.PreOrder();
	return 0;
}

16

构造连通图使构造所消耗代价最小

total submissions: 917times

passed: 333times

passing rate: 36.31%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

一个无向图  中包含  个点和  条边。矩阵  的第  行第  列元素  表示如果第  个点和第  个点没有联通的情况下,在这两个点之间构造一条边的代价。你的任务是在图中不断构造新的边使得整个图变成连通图,并且构造所消耗的代价最小。最终输出该代价和。 点的编号从1开始。

Input Format

第一行为一个数 ,表示图中点的个数。 

而后的  行都由  个被空格分隔的数组成,第  行第  列表示第  个点和第  个点没有联通的情况下,在这两个点之间构造一条边的代价(即这  行  列为矩阵 )。 

而后为一个数 ,表示图中已经存在的边的数量。 

而后的  行都由两个被空格分隔的数组成,分别是已经存在的边相连接的两个点 和  。

Output Format

输出一个数,表示新增加的边的代价和。

sample inpput and output

样例1

input:

4
0 6692 8925 9679
6692 0 9526 656
8925 9526 0 2664
9679 656 2664 0
2
1 3
1 2

output:

656

#include <iostream>
using namespace std;
int find(int* p, int key)
{
 int index = key;
 while (p[index] != index)
 {
  index = p[index];
 }
 return index;
}
void allset(int* p, int n1, int n2)
{
 int r1 = find(p, n1);
 int r2 = find(p, n2);
 if (r1 == r2)
  return;
 else
  p[r1] = r2;
 return;
}
void findmin(int** q, int n, int a[])
{
 int min = q[0][0];
 for (int i = 0; i < n; i++)
 {
  for (int j = 0; j < n; j++)
  {
   if (q[i][j] < min)
   {
    min = q[i][j];
    a[0] = i+1;
    a[1] = j+1;
   }
  }
 }
 q[a[0] - 1][a[1] - 1] += 9999999;
}
int main()
{
 int n;
 cin >> n;
 int* p = new int[n+1];
 p[0] = 0;
 for (int i = 1; i < n + 1; i++)
  p[i] = i;
 int** q = new int* [n];
 for (int i = 0; i < n; i++)
  q[i] = new int[n];
 for (int i = 0; i < n; i++)
 {
  for (int j = 0; j < n; j++)
  {
   cin >> q[i][j];
  }
 }
 int m;
 cin >> m;
 int k1,k2 ;
 for (int i = 0; i < m; i++)
 {
  cin >> k1 >> k2;
  allset(p, k1, k2);
  q[k1 - 1][k2-1] = 9999999;
 }
 for (int i = 0; i < n; i++)
  q[i][i] = 9999999;
 int k12[2];
 int sum = 0;
 while (m != n - 1)
 {
  findmin(q, n, k12);
  if(find(p,k12[0])==find(p,k12[1]))
  {
   ;
  }
  else 
  {
   allset(p, k12[0], k12[1]);
   m++;
   sum += q[k12[0] - 1][k12[1] - 1] - 9999999;
  }
 }
 cout <<sum;
 return 0;

}

17

消除连通图多余的边

total submissions: 752times

passed: 334times

passing rate: 44.41%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

一个连通图中有  个点和  条边 (  > ) 。每条边都有对应的权值。题目需要你删除权值较大的边以消除多余的边,同时保证图的连通性。最终输出所有被删除的边的权值和。点的编号从1开始。

Input Format

第一行两个正整数  和 ,分别代表点的数量和边的数量。 

之后  行每行有三个整数  分别表示边的两段端点序号和边的权值。

Output Format

输出一个正整数,代表所有被删除边的权值和。

sample inpput and output

样例1

input:

5 5
1 2 8
1 3 1
1 5 3
2 4 5
3 4 2

output:

8

#include<iostream>
using namespace std;
int findmin(int**a,int m)
{
    int k = a[0][2];
    int ki=0;
    for (int i = 0; i < m; i++)
    {
        if (a[i][2] < k)
        {
            k = a[i][2];
            ki = i;
        }
    }
    a[ki][2] += 1000;
    return ki;
}
int find(int* p, int key)
{
    int index = key;
    while (p[index] != index)
    {
        index = p[index];
    }
    return index;
}
bool unionset(int* p, int n1, int n2)
{
    int r1 = find(p, n1);
    int r2 = find(p, n2);
    if (r1 == r2)
        return false;
    else
    {
        p[r2] = p[r1];
    }
    return true;
}
int main()
{
 int n, m;
 cin >> n >> m;
 int* p = new int[n+1];
    p[0] = 0;
    for (int i = 1; i < n+1; i++)
     {
        p[i] = i;
     }
    int** q = new int* [m];
    for (int i = 0; i < m; i++)
    {
        q[i] = new int[3];
    }
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            cin >> q[i][j];
        }
    }
    int tog = 0;
    for (int i = 0; i < m; i++)
    {
        int x = findmin(q, m);
        if (find(p, q[x][0]) == find(p, q[x][1]))
        {
            tog += q[x][2] - 1000;
        }
        else
        {
            unionset(p, q[x][0], q[x][1]);
        }
    }
    cout << tog;
    return 0;


}

18

Dijkstra单源最短路径

total submissions: 1193times

passed: 353times

passing rate: 29.59%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

一个有向图中有  个顶点和  条单向路径 , 请使用Dijkstra算法,求出某一个顶点到其他顶点的最短路径。

Input Format

第一行两个正整数  和 ,分别代表点的数量和路径的数量。   1< <20, 0<=  <50

之后  行每行有三个整数  分别表示 路径 的起点、终点序号和路径长度。顶点编号从1开始,0<i,j<=n,0<k<100

源点编号p ,0<p<=n

Output Format

Ⅰ.Dijkstra计算过程;

Ⅱ.输出给定点v到其他各点的路径,以及最短距离。

注意输出格式。橘色点代表空格。CRLF代表换行。

按照Dijkstra算法获取最短路径顺序进行输出,如果没有路径则输出“No Path to ”【顶点编号,升序排列,中间使用空格隔开】

sample inpput and output

样例1

input:

8 10
1 6 10
1 5 5
6 3 1
6 5 2
3 4 4
4 1 7
4 3 6
5 6 3
5 3 9
5 4 2
1

output:

No.1 : 1 -> 5 , d = 5
No.2 : 1 -> 5 -> 4 , d = 7
No.3 : 1 -> 5 -> 6 , d = 8
No.4 : 1 -> 5 -> 6 -> 3 , d = 9
No.5 : No Path to 2 7 8

#include<iostream>
#include<stack>

using namespace std;

struct edge
{
	int bg, ed, val;
	edge(int p = 0,int q = 0,int v = -1):bg(p), ed(q), val(v){}
};

struct Node
{
	int flag;//标示结点是否已被访问。 
	Node(int f = 0):flag(f){}
};
//存储距离该结点最近的点以及路径长 
struct path
{
	int length, k;
	path(int l = 101,int kk = 0):length(l),k(kk){}
	path(const path& p)
	{
		length = p.length;
		k = p.k;
	}
};
//得到距离该点最近的点的路径长度 
int minpath(int bg, int ed, edge* e, int m)
{
	if(bg == ed)return 0;
	int min = 101;
	for(int i = 0;i < m; i++)
		if(e[i].bg == bg && e[i].ed == ed && e[i].val < min)
			min = e[i].val;

		return min;
}

int main()
{
	int n, m, t1, t2, t3, s;
	cin >> n >> m;
	edge* e = new edge[m];
	Node* N = new Node[n];
	int* pre = new int[n];//与当前结点相连的前一个点。 
	path* p = new path[n];
    
   
	for(int i = 0; i < n; i++)
		p[i].k = i;

	for(int i = 0; i < n; i++)
		pre[i] = -1;

	for(int i = 0; i < m; i++)
	{
		cin >> t1 >> t2 >> t3;
		e[i].bg = t1 - 1;
		e[i].ed = t2 - 1;
		e[i].val = t3;
	}
	cin >> s;
	s -= 1;
	pre[s] = s;
	p[s].length = 0;
	N[s].flag = 1;

	int* key = new int[n];
	for(int i = 0; i < n; i++)
	{
		p[i].length = minpath(s, i, e, m);
		key[i] = p[i].length;//暂存各结点的最短路径。 
	}

	int c1, c2;
	c1 = s;//从源点开始搜寻。 
	for(int i = 0; i < n - 1; i++)
	{
		for(int j = 0; j < n; j++)
		{
			if(N[j].flag == 1)continue;//已访问,直接跳到下一个结点。 
			if(key[j] > (key[c1] + minpath(c1, j, e, m)))
				{
					key[j] = key[c1] + minpath(c1, j, e, m);
					pre[j] = c1;
				}
		}
		int min = 101, j = 0;;
		for(;j < n; j++)
		{
			if(N[j].flag == 1)continue;
			if(key[j] <= min)
				{
					min = key[j];
					c2 = j;
				}
		}
		
		N[c2].flag = 1;
		if(i == 0)pre[c2] = c1;
		p[c2].length = key[c2];
		c1 = c2;
	}

	for(int i = 0; i < n; i++)
		for(int j = i + 1; j < n; j++)
			if(p[j].length < p[i].length)
			{
				path pp = p[j];
				p[j] = p[i];
				p[i]= pp;
			}

	int count = 1, flag = 0;
	for(int i = 0; i < n; i++)
	{
		int num = p[i].k;
		if(p[i].k == s)continue;
		if(p[i].length == 101)
		{
			flag++;
			continue;
		}

		stack<int> st;
		st.push(num);
		while(pre[num] != s)
		{
			st.push(pre[num]);
			num = pre[num];
		}

		cout << "No." << count++ << " : " << s + 1 << " ";
		while(!st.empty())
		{
			cout << "-> " << st.top() + 1 << " ";
			st.pop();
		}
		cout << ", d = " << p[i].length << endl;
	}

	if(flag > 0)
	{
	cout << "No." << count << " : No Path to";
	int *np = new int[flag];
	int q = 0;
	for(int i = 0; i < n; i++)
	{
		if(p[i].length == 101) np[q++] = p[i].k + 1;
	}

	for(int i = 0;i < flag; i++)
		for(int j = i + 1; j < flag; j++)
			if(np[j] < np[i])
			{
				int tmp = np[j];
				np[j] = np[i];
				np[i] = tmp;
			}

	for(int i = 0; i < flag; i++)cout << " " << np[i];
	}

	return 0;

}

19

ds-多源最短路径

total submissions: 917times

passed: 350times

passing rate: 38.17%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

一个有向图中有  个顶点和  条单向路径 , 试求任意两地点间最短距离。

Input Format

第一行两个正整数  和 ,分别代表点的数量和路径的数量。   0< <20, 0<=  <50

之后  行每行有三个整数  分别表示 路径 的起点和终点序号和路径长度。顶点编号从0开始,0<=i,j<n,0<k

Output Format

顶点之间最短路径矩阵(n*n),-1代表不连通。

每一行的最后一个数字后面没有空格。

sample inpput and output

样例1

input:

3 5
0 1 6
0 2 13
1 0 10
1 2 4
2 0 5

output:

0 6 10
9 0 4
5 11 0

样例2

input:

6 0

output:

0 -1 -1 -1 -1 -1
-1 0 -1 -1 -1 -1
-1 -1 0 -1 -1 -1
-1 -1 -1 0 -1 -1
-1 -1 -1 -1 0 -1
-1 -1 -1 -1 -1 0

#include<iostream>
using namespace std;

# define MaxInt 32767 
# define Num 100

typedef int VertexType;
typedef int ArcType;

typedef struct {
	VertexType vexs[Num];
	ArcType arcs[Num][Num];
	int vnum, anum;
}Graph;

ArcType D[Num][Num];
int Path[Num][Num];

void InitAMGraph(Graph& G) {
	cin >> G.vnum >> G.anum;
	for (int i = 0; i < Num; i++) {
		for (int j = 0; j < Num; j++) {
			if (i != j) {
				G.arcs[i][j] = MaxInt;
			}
			else {
				G.arcs[i][j] = 0;
			}
		}
	}
	for (int i = 0; i < G.vnum; i++) {
		G.vexs[i] = i;
	}
	int i, j;
	int weight;
	for (int k = 0; k < G.anum; k++) {
		cin >> i; cin >> j; cin >> weight;
		G.arcs[i][j] = weight;
	}
}

void Floyd(Graph G) {

	for (int i = 0; i < G.vnum; i++) {
		for (int j = 0; j < G.vnum; j++) {
			D[i][j] = G.arcs[i][j];
			if (D[i][j] < MaxInt && i != j) {
				Path[i][j] = i;
			}
			else {
				Path[i][j] = -1;
			}
		}
	}

	for (int k = 0; k < G.vnum; k++) {
		for (int i = 0; i < G.vnum; i++) {
			for (int j = 0; j < G.vnum; j++) {
				if (D[i][k] + D[k][j] < D[i][j]) {
					D[i][j] = D[i][k] + D[k][j];
					Path[i][j] = Path[k][j];
				}
			}
		}
	}
}

void OutputD(Graph G) {
	for (int i = 0; i < G.vnum; i++) {
		for (int j = 0; j < G.vnum; j++) {
			if (j == 0) {
				if (D[i][j] == MaxInt)
					cout << -1;
				else
					cout << D[i][j];
			}
			else {
				if (D[i][j] == MaxInt)
					cout << ' ' << -1;
				else
					cout << ' ' << D[i][j];
			}
		}
		cout << endl;
	}
}

int main() {
	Graph G;
	InitAMGraph(G);
	Floyd(G);
	OutputD(G);
	return 0;
}

20

ds-工程最短消耗

total submissions: 994times

passed: 316times

passing rate: 31.79%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

给出一个工程中N个阶段的时间消耗和依赖关系,试求出工程的最短时间消耗。

Input Format

输入N 0<N<=20。

随后输入N行数据,每行包含从1起始的阶段编号S、时间消耗T、以及用分号隔开的所依赖的不同阶段编号【如果不依赖其他阶段则此项为空】

Output Format

输出一行,为完成N个阶段的时间消耗。如果依赖关系不为DAG则输出"error"

sample inpput and output

样例1

input:

4
1 3
2 4
3 5 1;2;
4 3 3;

output:

12

样例2

input:

4
1 3 3;
2 4
3 5 1;2;
4 3 3;

output:

error

#include<iostream>
#include<string>
#include<queue>
using namespace std;

int loop(int a[20][20],int N)//判断依赖关系是否成立 
{
	queue<int> q;
	int* in = new int[N];
	int* visit = new int[N];
	for(int i = 0; i < N; i++) 
	{
		in[i] = 0;
		visit[i] = 0;
	}

	for(int i = 0; i < N; i++)
	{
		for(int j = 0; j < N; j++)
		{
			if(a[i][j] != -1)
				in[j]++;				
	    }
	}

	for(int i = 0; i < N; i++)
	{
		if(in[i] == 0)
		{
			q.push(i);
			visit[i] = 1;
			break;
		}		
	}

	while(!q.empty())
	{
		int t = q.front();
		for(int i = 0; i < N; i++)
		{
			if(a[t][i] != -1) in[i]--;
		}
		for(int i = 0; i < N; i++)
		{
			if(in[i] == 0 && visit[i] == 0)
			{
				q.push(i);
				visit[i] = 1;
		    }			
		}

		q.pop();
	}

	for(int i = 0; i < N; i++)
	{
		if(visit[i] == 0)return -1;
	}

	return 0;

}

int maxpath(int s, int a[20][20], int N, int* e)
{
	int* et = new int[N];
	int* flag = new int[N];
	for(int i = 0; i < N; i++)
		{
			et[i] = 0;
			flag[i] = 0;
		}

	queue<int> q;
	q.push(s);
	while(!q.empty())
	{
		int t = q.front();
		for(int i = 0; i < N; i++)
			if(a[t][i] != -1)
			{
				q.push(i);
				et[i] = (et[i] > et[t] + a[t][i]) ? et[i] : et[t] + a[t][i];
				flag[t] = 1;//后面的时间已包括该阶段消耗时间; 
			}

		q.pop();
	}

	for(int i = 0; i < N; i++)
		et[i] += e[i];

	int max = 0;
	for(int i = 0; i < N; i++)
	{
		if(flag[i] == 0 && et[i] > max) 
		{
			max = et[i];
		}
    }
		

	return max;
}

int main()
{
	int N;
	string s;
	cin >> N;
	getchar();
	int a[20][20];
	int* e = new int[N];
	
	for(int i = 0; i < N; i++)
	{
		for(int j = 0; j < N; j++)
			a[i][j] = -1;		
	}


	for(int i = 0; i < N; i++)
	{
		getline(cin, s);//istream& getline ( istream &is , string &str , char delim );默认的char delim为'\n'; 
		int k = 2;
		if(s[k] == ' ') k++;

		if((k + 1 < s.length() && s[k + 1] == ' ') || k == s.length() - 1)
			{
				e[i] = s[k] - '0';//存入活动消耗的时间 
				k += 2;
				
			}
		else 
		{
			e[i] = 10 * (s[k] - '0') + s[k + 1] - '0';
			k += 3;
		}

		while(k + 1 < s.length())
		{
			if(s[k+1] == ';')
				{
					a[s[k] - '0' - 1][i] = s[k] - '0' - 1;
					k += 2;
				}
			else 
			{
				a[(s[k] - '0' - 1) * 10 + s[k + 1]- '0' - 1][i] = (s[k] - '0' -1 ) * 10 + s[k + 1] -'0' - 1;
				k += 3;
			}
		}
	}

	for(int i = 0; i < N; i++)
	{
		for(int j = 0; j < N; j++)
		{
			if(a[i][j] != -1) a[i][j] = e[a[i][j]];				
		}	
	}


	if(loop(a,N) == -1)
	{
		cout << "error" << endl;
		return 0;
	}
	else
	{
	    int max = 0;
		for(int i = 0; i < N; i++)
		{
			int flag = 0;
			for(int j = 0; j < N; j++)
			{
				if(a[j][i] != -1)
					{
						flag = 1;
						break;
					}				
			} 
			if(flag == 0)
				{
					int t = maxpath(i, a, N, e);
					if(t > max)max = t;
			    }
	    }

	cout << max << endl;
	
	return 0;
	}
}

21

ds-快速排序算法

total submissions: 1187times

passed: 287times

passing rate: 24.18%

memory limit: 10485760(BYTE)

time limit: 10000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

使用快速排序算法将n个整数由小到大进行排序。并输出快排的第一趟排序结果以及最终的有序序列。

快速排序选取完pivot之后的进行整理的实现方法有很多,其中一种为”(前后指针法)“根据下面的描述进行实现并按要求输出,

以排序序列的最后一个值作为标准值pivot。

交换法:

选取最后一个关键字( pivot  )作为枢轴。
设置两个变量left = 0;right = N - 2;
从left一直向后走,直到找到一个大于等于 pivot   的值,right从后至前,直至找到一个小于 pivot   的值,然后交换这两个数。
重复第三步,一直往后找,直到left和right相遇,然后将 pivot 放置合适位置即可
 

输入:

n表示输入序列的长度,后边为n个要排序的整数序列,以空格分隔;

输出:

第一趟排序结果,以空格分隔,行尾无空格;

最终的有序序列结果,以空格分隔,行尾无空格;

sample inpput and output

样例1

input:

10 4 1 7 6 9 2 8 0 3 5

output:

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

样例2

input:

10 9 1 3 8 23 5 7 10 29 19

output:

9 1 3 8 10 5 7 19 29 23
1 3 5 7 8 9 10 19 23 29

#include <iostream>
#include <algorithm>
using namespace std;

void first_round(int arr[],int left,int right,int n){
    int pviot=arr[n];
    while (left < right) {
        while (arr[left] < pviot && left < right)
            left++;
        while (arr[right] >= pviot && left < right)
            right--;
        swap(arr[left], arr[right]);
    }
    if (arr[left] >= arr[n])
        swap(arr[left], arr[n]);
    else
        left++;
}
void quick_sort(int arr[], int start, int end) {
    if (start >= end)
        return;
    int mid = arr[end];
    int left = start, right = end - 1;
    while (left < right) {
        while (arr[left] < mid && left < right)
            left++;
        while (arr[right] >= mid && left < right)
            right--;
        swap(arr[left], arr[right]);
    }
    if (arr[left] >= arr[end])
        swap(arr[left], arr[end]);
    else
        left++;
    if (left) {
        quick_sort(arr, start, left - 1);
    }
    quick_sort(arr, left + 1, end);
}

int main(){
    int n;
    int i,j;
    cin>>n;
    int a[n],b[n];
    for(i=0;i<n;i++){b[i]=a[i];
        cin>>a[i];
        b[i]=a[i];
    }
    first_round(a, 0, n-2,n-1);
    for(j=0;j<n-1;j++){
        cout<<a[j]<<" ";
    }
    cout<<a[j]<<endl;
    quick_sort(b, 0, n-1);
    for(j=0;j<n-1;j++){
        cout<<b[j]<<" ";
    }
    cout<<b[j]<<endl;
}

22

ds-希尔排序的间隔

total submissions: 906times

passed: 308times

passing rate: 34.00%

memory limit: 10485760(BYTE)

time limit: 1000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

假设输入的序列为希尔排序的中间结果,请输出当前序列的最小间隔。

Input Format

输入N 0<N<=20。

随后输入N个整数

Output Format

序列排序的最小间隔  

sample inpput and output

样例1

input:

3
1 2 3

output:

1

样例2

input:

15
18 13 5 9 10 9 19 24 17 20 17 9 20 24 21

output:

6

#include <iostream>
#include <algorithm>
using namespace std;


void judge(int n,int*arr,bool p){
    for(int step=1;step<n;step++)
    {
        p = true;
        for(int i=step;i<n;i++)
        {
            for(int j=i;j>=step;j-=step)
            {
                if(arr[j-step]>arr[j])
                {
                    p = false;
                }
                else
                continue;
            }
        }
        if(p==true)
        {
            cout<<step<<endl;
            break;
        }
        else
        continue;
    }
}

int main(){
    int len;
    cin>>len;
    int a[len];
    for(int i=0;i<len;i++){
        cin>>a[i];
    }
    bool p=true;
    judge(len, a, p);
    return 0;
}

23

ds-判断排序方法

total submissions: 691times

passed: 290times

passing rate: 41.97%

memory limit: 10485760(BYTE)

time limit: 10000(MS)

input limit: 1000(line)

output limit: 1000(line)

question description

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成N个只包含1个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下1个有序的序列。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数N (<=100);随后一行给出原始序列的N个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:

首先在第1行中输出“Insertion Sort”表示插入排序、或“Merge Sort”表示归并排序;然后在第2行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行末不得有多余空格。

sample inpput and output

样例1

input:

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

output:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

样例2

input:

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

output:

Merge Sort
1 2 3 8 4 5 7 9 0 6

#include<iostream>
#include<algorithm>
using namespace std;
int a[200],b[200]; //a是原数组,b是中间序列数组;
int main()
{
    int N,j,i;
    cin>>N;
    for( i=0;i<N;i++)
        scanf("%d",&a[i]);
    for(i=0;i<N;i++)
        scanf("%d",&b[i]);
    int flag=-1,tag=1,count=0,dex;
    for( i=1;i<N;i++){//判断是归并还是插入
        if(count<1){
            if(b[i]<b[i-1])
            {
                tag=0;
                dex=i;//记录不符合非递减规则的第一个出现元素的下标
                count++;
            }
        }
        if(tag==0)
        {
            if(a[i]==b[i])
               flag=1;
            else{
                flag=0;
                break;
            }
        }
    }
    if(flag){//插入
         cout<<"Insertion Sort"<<endl;
        sort(b,b+dex+1);
         for(j=0;j<N-1;j++)
            cout<<b[j]<<" ";
        cout<<b[j]<<endl;
    }
    else {//归并
        cout<<"Merge Sort"<<endl;
        int cnt1=1,cnt2=1,cnt,m=0,z=0;
        for(i=1;i<N;i++)//判断头两个相邻非递减序列的长度,cnt1和cnt2;
        {
            if(m<1){
                if(b[i]>=b[i-1])
                       cnt1++;
                else
                    m++;
            }
            else{
                if(b[i]>=b[i-1])
                       cnt2++;
                else
                    break;
            }
        }
        cnt=cnt1<cnt2?cnt1:cnt2;//取cnt1和cnt2的较小值
        int x=N/(2*cnt)*(2*cnt);
        while(z+2*cnt<=N){
            sort(b+z,b+z+2*cnt);
            z+=2*cnt;
        }
        if(N%(2*cnt)!=0){//末尾元素得处理
            sort(b+x,b+N);
        }
        for( j=0;j<N-1;j++)
            cout<<b[j]<<" ";
        cout<<b[j]<<endl;
    }
    return 0;
 }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值