数据结构实验题

文章目录

      • 多项式运算
      • 火车站
      • Web导航
      • 表达式计算
      • DS栈—波兰式,逆波兰式
      • 银行单队列多窗口模拟
      • DS队列-组队列(不适用STL队列)
      • 最长重复子串
      • 计算一个串的最长真前后缀
      • KMP算法
      • 特殊的语言
      • 串替换
      • 二叉树构建和便利
      • 同一颗二叉树
      • 赫夫曼树的构建和编码
      • 赫夫曼树解码
      • 带权路径和
      • 二叉树最大路径
      • 二叉树的中后序遍历及求叶子
      • 二叉树镜面反转
      • 【id:76】【20分】B. DS二叉树—二叉树结点的最大距离
      • 【id:72】【10分】C. DS树--二叉树高度
      • 完全二叉树的根
      • 】【20分】E. 图综合练习--构建邻接表
      • 【id:93】【20分】F. DS图—图的邻接矩阵存储及度计算
      • 图深度优先搜索
      • 【id:88】【10分】B. DS图遍历--广度优先搜索
      • 【id:90】【10分】E. 图的应用之——图的连通
      • 最小生成树
      • . 货币套汇(图路径)
      • id:104】【10分】C. 拓扑排序-STL版
      • 【id:95】【20分】D. DS图—图的最短路径(不含代码框架)
      • 【id:102】【20分】F. 道路建设 (Ver. I)
      • DS二叉排序树之创建和插入
      • 二叉平衡树练习

多项式运算

【id:33】【20分】D. DS线性表—多项式运算
时间限制
1s
内存限制
128MB
题目描述

对于一元多项式 p(x)=p0+p1x+p2x2+ … +pnxn ,每个项都有系数和指数两部分,例如p2x2的系数为p2,指数为2。

编程实现两个多项式的加法、减法、乘法。

例如:多项式A = 5+x+2x2,多项式B = -x+4x4,计算:

A+B = 5+2x2+4x4

A-B = 5 + 2x +2x2 - 4x4

A*B = -5x - x2 -2x3 +20x4 + 4x5+8x6

实现方法不限,可以使用容器。

输入

测试次数t,每组测试数据格式如下:

第一行,第一个多项式A的项数n(n>0)

第二行,A的每一项的系数 指数(共2n个数字,均为整数,以空格分隔)

第三行,第一个多项式B的项数m(m>0)

第四行,B的每一项的系数 指数(共2m个数字,均为整数,以空格分隔)

输出

对每组测试数据,输出五行,分别是:

多项式A

多项式B

A+B

A-B

A*B

每组测试数据间以空行分隔。

多项式输出格式:项之间用+连接,例如,1 + x 。但后一项系数为负数,不输出+号,如: 1 + (-2x2),输出为1 - 2x^2。

如果该项:系数为0,不输出,但表达式只有一项0,要输出。

指数为0,不输出x0。指数为负数,例如-3,输出x(-3)。指数为正数,例如3,输出x^3。指数为1,输出x。

以上一句话总结:和数学中多项式表示相同,x的指数加^表示。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
2
1 0 1 1
2
-1 0 -1 1
3
5 0 1 1 2 2
2
-1 1 4 4

输出样例1
1+x
-1-x
0
2+2x
-1-2x-x^2

5+x+2x^2
-x+4x^4
5+2x2+4x4
5+2x+2x2-4x4
-5x-x2-2x3+20x4+4x5+8x^6

#include
using namespace std;
#include 
#include

void initList(list<pair<int, int>>& list, int term)
{
	for (int i = 0; i < term; i++)
	{
		int coef, expn;
		cin >> coef >> expn;
		list.push_back(make_pair(coef, expn));
	}
}
list<pair<int, int>>APlusB(const list<pair<int, int>>& list1, const list<pair<int, int>>& list2)
{
	list<pair<int, int>>list3;
	auto qa = list1.begin();
	auto qb = list2.begin();
	while (qa != list1.end() && qb != list2.end())
	{
		if ((*qa).second == (*qb).second)
		{
			int  x = (*qa).first + (*qb).first;
			if (x)
			{
				list3.push_back(make_pair(x, (*qa).second));
				qa++;
				qb++;
			}
			else
			{
				qa++;
				qb++;
			}
		}
		else if ((*qa).second < (*qb).second)
		{
			list3.push_back(*qa);
			qa++;
		}
		else
		{
			list3.push_back(*qb);
			qb++;
		}
	}
	if (qa == list1.end())
	{
		while (qb != list2.end())
		{
			list3.push_back(*qb);
			qb++;
		}
	}
	else
	{
		while (qa != list1.end())
		{
			list3.push_back(*qa);
			qa++;
		}
	}
	return list3;

}
list<pair<int, int>>ASubB(const list<pair<int, int>>& list1, const list<pair<int, int>>& list2)
{
	list<pair<int, int>>list3;
	auto qa = list1.begin();
	auto qb = list2.begin();
	while (qa != list1.end() && qb != list2.end())
	{
		if ((*qa).second == (*qb).second)
		{
			int  x = (*qa).first - (*qb).first;
			if (x)
			{
				list3.push_back(make_pair(x, (*qa).second));
				qa++;
				qb++;
			}
			else
			{
				qa++;
				qb++;
			}
		}
		else if ((*qa).second < (*qb).second)
		{
			list3.push_back(*qa);
			qa++;
		}
		else
		{
			list3.push_back(make_pair(-(*qb).first, (*qb).second));
			qb++;
		}
	}
	if (qa == list1.end())
	{
		while (qb != list2.end())
		{
			list3.push_back(make_pair(-(*qb).first, (*qb).second));
			qb++;
		}
	}
	else
	{
		while (qa != list1.end())
		{
			list3.push_back(*qa);
			qa++;
		}
	}
	return list3;

}
void print(list<pair<int, int>>list)
{
	if (list.empty())
	{
		cout << '0' << endl;
		return;
	}
	int flagForZero = 0;
	for (auto p = list.begin(); p != list.end(); p++)
	{
		if ((*p).first != 0)
		{
			flagForZero = 1;
		}
	}
	if (flagForZero == 0)
	{
		cout << '0' << endl;
		return;
	}
	int flag = 0;
	for (auto p = list.begin(); p != list.end(); p++)
	{
		/*if ((*p).first < 0)
		{
			cout << "-";
		}*/
		if ((*p).first == 0)continue;
		if ((*p).first > 0)
		{
			if (flag != 0)
			{
				cout << "+";
			}
		}
		if ((*p).second != 0)
		{
			if ((*p).first != 1&&(*p).first!=-1)
			{
				cout << (*p).first;
			}
			else if ((*p).first == -1)
			{
				cout << "-";
			}
			if ((*p).second == 1)
			{
				cout << "x";
			}
			else
			{
				cout  << "x^";
				if ((*p).second < 0)
				{
					cout << "(" << (*p).second << ")";
				}
				else
				{
					cout << (*p).second;
				}
			}
		}
		else
		{
			cout << (*p).first;
		}
		flag++;
	}
	cout << endl;
}
list<pair<int,int>> AMulB(list<pair<int, int>>list1, list<pair<int, int>>list2)
{
	list<pair<int, int>>list4;
	for (auto q=list2.begin();q!=list2.end(); q++)
	{

		list<pair<int, int>>list3;
		for (auto p = list1.begin(); p != list1.end(); p++)
		{
			int coef = (*p).first * (*q).first;
			int expn = (*p).second + (*q).second;
			list3.push_back(make_pair(coef, expn));
		}
		list4 = APlusB(list4, list3);
	}
	return list4;
}
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int termFirst;
		cin >> termFirst;
		list<pair<int,int>>list1;
		initList(list1, termFirst);
		int termSecond;
		cin >> termSecond;
		list<pair<int, int>>list2;
		initList(list2, termSecond);
		print(list1);
		print(list2);
		list<pair<int, int>>list3 = APlusB(list1, list2);
		print(list3);
		list3 = ASubB(list1, list2);
		print(list3);
		list3 = AMulB(list1, list2);
		print(list3);
		cout << endl;
	}
}

火车站

【id:139】【10分】E. 火车站(stack)
时间限制
1s
内存限制
128MB
题目描述

火车站只有一条铁路,所有的火车都停在那里。所以所有的火车都是从一边进站,从另一边出站。如果A列先进入铁路,然后B列在A列离开之前进入铁路,那么A列在B列离开之前不能离开。下图说明了问题所在。车站里最多有9列火车,所有的火车都有一个ID(编号从1到N),火车按照O1的顺序进入火车,火车是否可以按照O2的顺序驶出。

输入

输入包含几个测试用例。

每个测试用例由一个整数(列车数)和两个字符串组成。两个字符串分别为列车入站顺序和列车出站顺序。

输出

如果不能按照指定顺序出站,输出“No”。

如果可以,输出“Yes”,然后输出出入站顺序(对于进入铁路的列车,应输出“in”,对于出铁路的列车,应输出“out”)。在每个测试用例之后打印一行包含“FINISH”。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
3
3 123 321
3 abc cab
3 123 123
输出样例1
Yes
in
in
in
out
out
out
FINISH
No
FINISH
Yes
in
out
in
out
in
out
FINISH

#include
using namespace std;
#include
/火车站
typedef struct
{
	char* base;
	char* top;
	int maxSize;
}Stack;
void InitStack(Stack& s)
{
	s.base = (char*)malloc(100 * sizeof(char));
	s.top = s.base;
	s.maxSize = 100;
}
void push(Stack& s,char c)
{
	*s.top = c;
	s.top++;
}
char pop(Stack& s)
{
	if (s.top == s.base)
	{
		return 0;
	}
	return *(s.top--);
}
char top(Stack& s)
{
	if (s.top == s.base)
	{
		return 0;
	}
	return *(s.top - 1);
}
bool Empty(Stack& s)
{
	return s.base == s.top;
}
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		int trainCount;
		cin >> trainCount;
		string inOrder, outOrder;
		cin >> inOrder >> outOrder;
		Stack s;
		InitStack(s);
		vector<string>v;
		for (int i = 0; i < inOrder.length(); i++)
		{
			if (inOrder[i] != outOrder[0])
			{
				push(s,inOrder[i]);
				v.push_back("in");
			}
			else
			{
				outOrder.erase(0, 1);
				v.push_back("in");
				v.push_back("out");
			}
		}
		for (int i = 0; i < outOrder.size(); i++)
		{
			if (top(s) == outOrder[i])
			{
				v.push_back("out");
				pop(s);
			}
		}
		if (Empty(s))
		{
			cout << "Yes" << endl;
			for (auto s : v)
			{
				cout << s << endl;
			}
		}
		else
		{
			cout<<"No"<<endl;
		}
		cout << "FINISH" << endl;
	}
	cout << endl;
}

Web导航

标准Web浏览器包含在最近访问过的页面之间前后移动的功能。 实现这些功能的一种方法是使用两个堆栈来跟踪可以通过前后移动到达的页面。 在此问题中,系统会要求您实现此功能。
需要支持以下命令:
BACK:将当前页面推到前向堆栈的顶部。 从后向堆栈的顶部弹出页面,使其成为新的当前页面。 如果后向堆栈为空,则忽略该命令。
FORWARD:将当前页面推到后向堆栈的顶部。 从前向堆栈的顶部弹出页面,使其成为新的当前页面。 如果前向堆栈为空,则忽略该命令。
访问:将当前页面推送到后向堆栈的顶部,并将URL指定为新的当前页面。 清空前向堆栈。
退出:退出浏览器。
假设浏览器最初在URL http://www.acm.org/上加载网页

输入

测试数据只有一组

输入是一系列命令。 命令关键字BACK,FORWARD,VISIT和QUIT都是大写的。 URL没有空格,最多包含70个字符。 任何时候堆栈都不会超过100个元素。 输入结束由QUIT命令指示。

输出

对于除QUIT之外的每个命令,如果不忽略该命令,则在执行命令后输出当前页面的URL。否则,打印“Ignored”。 每个命令的输出应该在对应行上输出。 QUIT命令无输出。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
VISIT http://acm.ashland.edu/
VISIT http://acm.baylor.edu/acmicpc/
BACK
BACK
BACK
FORWARD
VISIT http://www.ibm.com/
BACK
BACK
FORWARD
FORWARD
FORWARD
QUIT
输出样例1
http://acm.ashland.edu/
http://acm.baylor.edu/acmicpc/
http://acm.ashland.edu/
http://www.acm.org/
Ignored
http://acm.ashland.edu/
http://www.ibm.com/
http://acm.ashland.edu/
http://www.acm.org/
http://acm.ashland.edu/
http://www.ibm.com/
Ignored

#include
#include
using namespace std;
typedef struct
{
	string* base;
	string* top;
	int maxSize;
}Stack;
void InitStack(Stack& s)
{
	s.base = new string[100];
	s.top = s.base;
	s.maxSize = 100;
}
void push(Stack& s, string c)
{
	*s.top = c;
	s.top++;
}
string pop(Stack& s)
{
	if (s.top == s.base)
	{
		return NULL;
	}
	string s1 = *(s.top - 1);
	*(s.top - 1) = "0";
	s.top--;
	return s1;
}
string top(Stack& s)
{
	if (s.top == s.base)
	{
		return NULL;
	}
	return *(s.top - 1);
}
bool Empty(Stack& s)
{
	return s.base == s.top;
}
void clear(Stack& s)
{
	s.top = s.base;
}
void web(Stack& s1, Stack& s2)
{
	string operation;
	cin >> operation;
	string curUrl = "http://www.acm.org/";
	while (operation != "QUIT")
	{
		if (operation == "VISIT")
		{
			push(s2, curUrl);
			string url;
			cin >> url;
			cout << url << endl;
			curUrl = url;
			clear(s1);
		}
		else if (operation == "BACK")
		{
			if(!Empty(s2))
			{
				push(s1, curUrl);
				curUrl = pop(s2);
				cout << curUrl << endl;
			}
			else
			{
				cout << "Ignored\n";
			}
		}
		else if (operation == "FORWARD")
		{
			
			if (!Empty(s1))
			{
				push(s2, curUrl);
				curUrl = pop(s1);
				cout << curUrl << endl;
			}
			else
			{
				cout << "Ignored\n";
			}
		}
		cin >> operation;
	}
	
}
int main()
{
	Stack forward;
	Stack backward;
	InitStack(forward);
	InitStack(backward);
	web(forward, backward);

}

表达式计算

【id:41】【10分】D. DS堆栈–表达式计算
时间限制
1s
内存限制
128MB
题目描述

计算一个表达式的运算结果

使用C++自带stack堆栈对象来实现

参考课本的伪代码(算法3.3P52),把伪代码改造成可运行的代码

例如

  1. Push (OPTR, ‘#’);表示把字符#压入堆栈OPTR中,转换成c++代码就是OPTR.push(‘#’);

  2. Pop(OPND, a); 表示弹出栈OPND的栈顶元素,并把栈顶元素放入变量a中。因此改成c++代码是两个操作:

    a = OPND.top(); OPND.pop();

  3. a = GetTop(OPND)表示获取栈OPND的栈顶元素,转成c++代码就是: a = OPND.top();

输入

第一个输入t,表示有t个实例

第二行起,每行输入一个表达式,每个表达式末尾带#表示结束

输入t行

输出

每行输出一个表达式的计算结果,计算结果用浮点数(含4位小数)的格式表示

用cout控制浮点数输出的小数位数,需要增加一个库文件,并使用fixed和setprecision函数,代码如下:

#include
#include
using namespace std;

int main()

{ double temp = 12.34

cout<

}

输出结果为12.3400

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
1+2*3-4/5#
(66+(((11+22)*2-33)/3+6)*2)-45.6789#

输出样例1
6.2000
54.3211

#include
#include
#include
#include
#include
#include
using namespace std;
#define OK 0
#define ERROR -1
#define OVERFLOW -1
#define OPSETSIZE 7
typedef int Status;
char Prior[7][7] = {//运算符间的优先关系
    '>','>','<','<','<','>','>',
    '>','>','<','<','<','>','>',
    '>','>','>','>','<','>','>',
    '>','>','>','>','<','>','>',
    '<','<','<','<','<','=',' ',
    '>','>','>','>',' ','>','>',
    '<','<','<','<','<',' ',' '
};
float Operate(float a, unsigned char theta, float b)
{
    switch (theta)
    {
    case '+':return a + b; break;
    case '-':return a - b; break;
    case '*':return a * b; break;
    case '/':return a / b; break;
    }
    return ERROR;
}
char opset[OPSETSIZE] = { '+', '-', '*', '/', '(', ')','#' };
Status in(char Test, char* Testop)
{
    for (int i = 0; i < OPSETSIZE; i++)
    {
        if (Test == Testop[i])
        {
            return OK;
        }
    }
    return ERROR;
}
char precede(char Aop, char Bop)
{
    int aIndex = 0;
    int bIndex = 0;
    for (int i=0; i < OPSETSIZE; i++)
    {
        if (Aop == opset[i])
        {
            aIndex = i;
        }
        if (Bop == opset[i])
        {
            bIndex = i;
        }
    }
    return Prior[aIndex][bIndex];
}
float EvaluateExpression(string Myexp)
{
    stack<char>OPTR;
    OPTR.push('#');
    stack<double>OPND;
    char TempData[20];
    double Data, a, b, r;
    char theta, Dr[2];
    char c;
    int i = 0;
    c = Myexp[i];
    strcpy(TempData, "\0");
    while (c != '#' || OPTR.top() != '#')
    {
        if (in(c, opset)==ERROR)
        {
            Dr[0] = c;
            Dr[1] = '\0';
            strcat(TempData, Dr);
            c = Myexp[++i];
            if (in(c,opset)==OK)
            {
                Data = (float)atof(TempData);
                OPND.push(Data);
                strcpy(TempData, "\0");
            }
        }
        else {
            switch (precede(OPTR.top(), c))
            {
            case '<':
                OPTR.push(c);
                c = Myexp[++i];
                break;
            case '=':
                OPTR.pop();
                c = Myexp[++i];
                break;
            case '>':
                theta = OPTR.top();
                OPTR.pop();
                a = OPND.top();
                OPND.pop();
                b = OPND.top();
                OPND.pop();
                OPND.push(Operate(b, theta, a));
                break;
            }
        }
    }
    return OPND.top();
}
int main() {

    string exp;
    int t;
    double result;
    cin >> t;
    while (t--) {
        cin >> exp;
        result = EvaluateExpression(exp);

        cout << fixed << setprecision(4) << result << endl;
    }
    return 0;
}

DS栈—波兰式,逆波兰式

题目描述

   表达式有三种表示方法,分别为:

前缀表示(波兰式):运算符+操作数1+操作数2

中缀表示:操作数1+运算符+操作数2

后缀表示(逆波兰式):操作数1+操作数2+运算符

例如:a +b * (c -d ) - e/f

波兰式:-+a*b-cd/ef     (运算符在操作数的前面,用递归计算波兰式)

中缀式:a+b*c-d-e/f  

逆波兰式:abcd-*+ef/-   (运算符在操作数的后面,用栈计算逆波兰式)

   中缀表示就是原表达式去掉扣号。       

 根据表达式求波兰式、逆波兰式都是教材第三章表达式求值的思想。     

  求波兰式,需要操作数栈(注意不是计算结果入栈,有计算式入栈),运算符栈。区别在于从后往前扫描表达式,‘(’ 换成')','('换成‘)’。栈顶运算符优先级>新读入运算符优先级出栈,教材第三章表3.1中的相同运算符优先级>(从左往右计算)改为<,例如栈顶为‘+‘,新读入的为‘+’,则栈顶优先级<新读入的优先级。

 求逆波兰式,只需要运算符栈。操作数直接输出,操作符按表3.1优先级顺序出栈,输出。

   输入表达式,求其波兰式和逆波兰式。

输入

测试次数

每组测试数据一行,一个合法表达式

输出

对每组测试数据,输出两行

第一行,表达式的波兰表示

第二行,表达式的逆波兰表示

不同组测试数据间以空行分隔。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
4+23-10/5
12+3
5+(2+10)*5

输出样例1

    • 4 * 2 3 / 10 5
      4 2 3 * + 10 5 / -
    • 12 * 3 5 * + 2 10 5
      12 3 5 * + 2 10 + 5 * +
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define OK 0
#define ERROR -1
#define OVERFLOW -1
#define OPSETSIZE 7
typedef int Status;
char Prior[7][7] = {//运算符间的优先关系
    '>','>','<','<','<','>','>',
    '>','>','<','<','<','>','>',
    '>','>','>','>','<','>','>',
    '>','>','>','>','<','>','>',
    '<','<','<','<','<','=',' ',
    '>','>','>','>',' ','>','>',
    '<','<','<','<','<',' ',' '
};

typedef struct
{
    char* base;
    char* top;
    int maxSize;
}Stack;
void InitStack(Stack& s)
{
    s.base = (char*)malloc(100 * sizeof(char));
    s.top = s.base;
    s.maxSize = 100;
}
void push(Stack& s, char c)
{
    *s.top = c;
    s.top++;
}
char pop(Stack& s)
{
    if (s.top == s.base)
    {
        return 0;
    }
    return *(s.top--);
}
char top(Stack& s)
{
    if (s.top == s.base)
    {
        return 0;
    }
    return *(s.top - 1);
}
bool Empty(Stack& s)
{
    return s.base == s.top;
}
char opset[OPSETSIZE] = { '+', '-', '*', '/', '(', ')','\0'};
Status in(char Test, char* Testop)
{
    for (int i = 0; i < OPSETSIZE; i++)
    {
        if (Test == Testop[i])
        {
            return OK;
        }
    }
    return ERROR;
}
char precede(char Aop, char Bop)
{
    int aIndex = 0;
    int bIndex = 0;
    for (int i = 0; i < OPSETSIZE; i++)
    {
        if (Aop == opset[i])
        {
            aIndex = i;
        }
        if (Bop == opset[i])
        {
            bIndex = i;
        }
    }
    return Prior[aIndex][bIndex];
}
void Poland(string ep)
{
    stack<char>OPTR;
    stack<string>OPND;
    string TempData = "\0";
    /*char theta, Dr[2];*/
    char Dr[2];
    char arr[2];
    int flag = 0;
    int i = ep.length() - 1;
    while(i>=0)
    {
        char c = ep[i];
        if (in(c, opset) == ERROR)
        {
            Dr[0] = c;
            Dr[1] = '\0';
            TempData += Dr;
            if (i == 0)
            {
                reverse(TempData.begin(), TempData.end());
                OPND.push(TempData);
                break;
            }
            c = ep[--i];
            if (in(c, opset) == OK)
            {
                reverse(TempData.begin(),TempData.end());
                OPND.push(TempData);
                TempData = "\0";
            }
        }
        else
        {
            if (OPTR.empty())
            {
                OPTR.push(c);
                c = ep[--i];
            }else
            {
                if (c == ')')
                {
                    OPTR.push(c);
                    c = ep[--i];
                }
                else if (c == '(')
                {
                    while (OPTR.top() != ')')
                    {
                        arr[0] = OPTR.top();
                        arr[1] = '\0';
                        OPTR.pop();
                        OPND.push(arr);
                    }
                    OPTR.pop();
                    c = ep[--i];
                }
                else
                {
                    switch (precede(c,OPTR.top()))
                    {
                    case '>':
                        OPTR.push(c);
                        c = ep[--i];
                        break;
                    case '<':
                    {
                        arr[0] = OPTR.top();
                        arr[1] = '\0';
                        OPTR.pop();
                        OPND.push(arr);
                    }break;                        
                    }
                }
            }
        }
    }
    while (!OPTR.empty())
    {
        arr[0] = OPTR.top();
        arr[1] = '\0';
        OPTR.pop();
        OPND.push(arr);
    }

    while (!OPND.empty())
    {
        if (flag++ == 0)
        {
            cout << OPND.top();
        }
        else
        {
            cout << " " << OPND.top();
        }
        OPND.pop();
   }
}
void AnTiPoland(string ep)
{
    stack<char>OPTR;    
    char c;
    int i = 0;
    c = ep[i];
    char TempData[20];
    char theta, Dr[2];
    strcpy(TempData, "\0");
    int flag = 0;
    while (c != '\0')
    {
        if (in(c, opset) == ERROR)
        {
            Dr[0] = c;
            Dr[1] = '\0';
            strcat(TempData, Dr);
            c = ep[++i];
            if (in(c, opset) == OK)
            {
                if (flag++ == 0)
                {
                    cout << TempData;
                }
                else
                {
                    cout << " " << TempData;
                }
                strcpy(TempData, "\0");
            }
        }
        else {
            if (OPTR.empty())
            {
                OPTR.push(c);
                c = ep[++i];
            }
            else
            {
                if (c == ')')
                {
                    while (OPTR.top() != '(')
                    {
                        if (flag++ == 0)
                        {
                            cout << OPTR.top();
                        }
                        else
                        {
                            cout << " " << OPTR.top();
                        }
                        OPTR.pop();
                    }
                    OPTR.pop();
                    c = ep[++i];
                    continue;
                }
                switch (precede(OPTR.top(), c))
                {
                case '<':
                    OPTR.push(c);
                    c = ep[++i];
                    break;
                case '>':
                    while (!OPTR.empty()&&precede(OPTR.top(), c))
                    {
                        if (flag++ == 0)
                        {
                            cout << OPTR.top();
                        }
                        else
                        {
                            cout << " " << OPTR.top();
                        }
                        OPTR.pop();
                    }
                    if (OPTR.empty())
                    {
                        OPTR.push(c);
                    }
                    c = ep[++i];
                    break;
                }
            }
        }
    }
    while (!OPTR.empty())
    {
        if (flag++ == 0)
        {
            cout << OPTR.top();
        }
        else
        {
            cout << " " << OPTR.top();
        }
        OPTR.pop();
    }
}
int main() {

    int t;
    cin >> t;
    while (t--)
    {
        string expression;
        cin >> expression;
        Poland(expression);
        cout << endl;
        AnTiPoland(expression);
        if (t != 0)
        {
            cout << endl;
            cout << endl;
        }
    }
}

银行单队列多窗口模拟

【id:50】【20分】D. DS队列----银行单队列多窗口模拟
时间限制
1s
内存限制
128MB
题目描述

假设银行有K个窗口提供服务,窗口前设一条黄线,所有顾客按到达时间在黄线后排成一条长龙。当有窗口空闲时,下一位顾客即去该窗口处理事务。当有多个窗口可选择时,假设顾客总是选择编号最小的窗口。

本题要求输出前来等待服务的N位顾客的平均等待时间、最长等待时间、最后完成时间。

输入

输入第1行给出正整数N(≤1000),为顾客总人数;随后N行,每行给出一位顾客的到达时间T和事务处理时间P,并且假设输入数据已经按到达时间先后排好了顺序;最后一行给出正整数K(≤10),为开设的营业窗口数。

输出

在一行中输出平均等待时间(输出到小数点后1位)、最长等待时间、最后完成时间,之间用1个空格分隔,行末不能有多余空格。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3

输出样例1
6.2 17 62

#include
using namespace std;
#include
#include
#include
int emptyIndex(vector<queue<pair<int,int>>>&v1)
{
	for (int i = 0; i < v1.size(); i++)
	{
		if (v1[i].empty())
		{
			return i;
		}
	}
	return -1;
}
void setTimeSecond(vector<queue<pair<int, int>>>& v1, int digit)
{
	for (int i = 0; i < v1.size(); i++)
	{

	}
}
void setTime(vector<queue<pair<int, int>>>&v1,int digit)
{
	int difference = -1;
	for (int i = 0; i < v1.size(); i++)
	{
		queue<pair<int, int>>q = v1[i];
		if (!q.empty())
		{
			difference = digit-q.front().first;
			break;
		}
	}
	for (int i = 0; i < v1.size(); i++)
	{
		queue<pair<int, int>>q = v1[i];
		if (!q.empty())
		{
			pair<int, int>p = q.front();
			if (p.first != digit)
			{
				p.second = p.second - difference;
				if (p.second <= 0)
				{
					p.second = 0;
				}
				p.first = digit;
			}
			q.pop();
			q.push(p);
			v1[i] = q;
		}
		else
		{
			continue;
		}
	}
}
int getMax(vector<queue<pair<int, int>>>& v)
{
	int max = 0;
	for (auto a : v)
	{
		if (!a.empty())
		{
			pair<int, int>p1 = a.front();
			if (p1.first + p1.second > max)
			{
				max = p1.first + p1.second;
			}
		}
	}
	return max;
}
int getMinAndPop(vector<queue<pair<int, int>>>& v1)
{
	int min = 1000000;
	int index = -1;
	for (int i = 0; i < v1.size(); i++)
	{
		queue<pair<int,int>> q=v1[i];
		if (!q.empty())
		{
			pair<int, int>p1 = q.front();
			if (p1.second <= min)
			{
				min = p1.second;
				index = i;
			}
		}
	}
	v1[index].pop();
	return min;
}
void Bank(vector<pair<int, int>>& v, int K)
{
	vector<queue<pair<int,int>>>v1;
	int timeLine = 0;时间线
	double waitTime = 0;
	int singleTime = 0;
	int LonggestTime = 0;
	int timeLineInQueue = -1;
	for (int i = 0; i < K; i++)
	{
		queue<pair<int,int>>q1;
		v1.push_back(q1);
	}
	for (int i = 0; i < v.size(); i++)
	{
		singleTime = 0;
		pair<int, int>p1 = v[i];
		int flag = emptyIndex(v1);
		if (flag != -1)
		{
			v1[flag].push(p1);
			timeLine = p1.first;
			setTime(v1, timeLine);
			timeLineInQueue = timeLine;
		}
		else                     
		{	
			timeLine = p1.first;
			if (timeLine > timeLineInQueue)
			{
				setTime(v1, timeLine);
			}
			else
			{
				singleTime += timeLineInQueue - timeLine;
				waitTime+= timeLineInQueue - timeLine;
				timeLine = timeLineInQueue;
				p1.first = timeLine;
			}
			int a = getMinAndPop(v1);
			singleTime += a;
			waitTime += a;
			setTime(v1, a + p1.first);
			if (LonggestTime < singleTime)
			{
				LonggestTime = singleTime;
			}
			p1.first += a;
			int flag = emptyIndex(v1);
			if (flag != -1)
			{
				v1[flag].push(p1);
			}
			timeLineInQueue = p1.first;
		}
	}
	int max = getMax(v1);
	printf("%.1f %d %d\n", waitTime / v.size(),LonggestTime,max);
}
int main()
{
	int N;
	cin >> N;
	vector<pair<int, int>>v1;
	for (int i = 0; i < N; i++)
	{
		int first, second;
		cin >> first >> second;
		v1.push_back(make_pair(first, second));
	}
	int K;
	cin >> K;
	Bank(v1, K);
	cout << endl;
}

DS队列-组队列(不适用STL队列)

【id:198】【20分】F. DS队列–组队列(不使用STL队列)
时间限制
1s
内存限制
128MB
题目描述

组队列是队列结构中一种常见的队列结构,在很多地方有着广泛应用。组队列是是指队列内的元素分组聚集在一起。组队列包含两种命令:

1、 ENQUEUE,表示当有新的元素进入队列,首先会检索是否有同一组的元素已经存在,如果有,则新元素排在同组的最后,如果没有则插入队列末尾。

2、 DEQUEUE,表示队列头元素出队

3、 STOP,停止操作

注意:不要使用C++自带的队列对象queue。

输入

第1行输入一个t(t<=10),表示1个队列中有多少个组

第2行输入一个第1组的元素个数和数值

第3行输入一个第2组的元素个数和数值

以此类推输入完t组以定义同组元素之后,开始输入多个操作命令(<200),对空的组队列进行操作,例如输入ENQUEUE 100,表示把元素100插入队列

#include
using namespace std;
#include
#include
#include
int emptyIndex(vector<queue<pair<int,int>>>&v1)
{
	for (int i = 0; i < v1.size(); i++)
	{
		if (v1[i].empty())
		{
			return i;
		}
	}
	return -1;
}
void setTimeSecond(vector<queue<pair<int, int>>>& v1, int digit)
{
	for (int i = 0; i < v1.size(); i++)
	{

	}
}
void setTime(vector<queue<pair<int, int>>>&v1,int digit)
{
	int difference = -1;
	for (int i = 0; i < v1.size(); i++)
	{
		queue<pair<int, int>>q = v1[i];
		if (!q.empty())
		{
			difference = digit-q.front().first;
			break;
		}
	}
	for (int i = 0; i < v1.size(); i++)
	{
		queue<pair<int, int>>q = v1[i];
		if (!q.empty())
		{
			pair<int, int>p = q.front();
			if (p.first != digit)
			{
				p.second = p.second - difference;
				if (p.second <= 0)
				{
					p.second = 0;
				}
				p.first = digit;
			}
			q.pop();
			q.push(p);
			v1[i] = q;
		}
		else
		{
			continue;
		}
	}
}
int getMax(vector<queue<pair<int, int>>>& v)
{
	int max = 0;
	for (auto a : v)
	{
		if (!a.empty())
		{
			pair<int, int>p1 = a.front();
			if (p1.first + p1.second > max)
			{
				max = p1.first + p1.second;
			}
		}
	}
	return max;
}
int getMinAndPop(vector<queue<pair<int, int>>>& v1)
{
	int min = 1000000;
	int index = -1;
	for (int i = 0; i < v1.size(); i++)
	{
		queue<pair<int,int>> q=v1[i];
		if (!q.empty())
		{
			pair<int, int>p1 = q.front();
			if (p1.second <= min)
			{
				min = p1.second;
				index = i;
			}
		}
	}
	v1[index].pop();
	return min;
}
void Bank(vector<pair<int, int>>& v, int K)
{
	vector<queue<pair<int,int>>>v1;
	int timeLine = 0;时间线
	double waitTime = 0;
	int singleTime = 0;
	int LonggestTime = 0;
	int timeLineInQueue = -1;
	for (int i = 0; i < K; i++)
	{
		queue<pair<int,int>>q1;
		v1.push_back(q1);
	}
	for (int i = 0; i < v.size(); i++)
	{
		singleTime = 0;
		pair<int, int>p1 = v[i];
		int flag = emptyIndex(v1);
		if (flag != -1)
		{
			v1[flag].push(p1);
			timeLine = p1.first;
			setTime(v1, timeLine);
			timeLineInQueue = timeLine;
		}
		else                     
		{	
			timeLine = p1.first;
			if (timeLine > timeLineInQueue)
			{
				setTime(v1, timeLine);
			}
			else
			{
				singleTime += timeLineInQueue - timeLine;
				waitTime+= timeLineInQueue - timeLine;
				timeLine = timeLineInQueue;
				p1.first = timeLine;
			}
			int a = getMinAndPop(v1);
			singleTime += a;
			waitTime += a;
			setTime(v1, a + p1.first);
			if (LonggestTime < singleTime)
			{
				LonggestTime = singleTime;
			}
			p1.first += a;
			int flag = emptyIndex(v1);
			if (flag != -1)
			{
				v1[flag].push(p1);
			}
			timeLineInQueue = p1.first;
		}
	}
	int max = getMax(v1);
	printf("%.1f %d %d\n", waitTime / v.size(),LonggestTime,max);
}
int main()
{
	int N;
	cin >> N;
	vector<pair<int, int>>v1;
	for (int i = 0; i < N; i++)
	{
		int first, second;
		cin >> first >> second;
		v1.push_back(make_pair(first, second));
	}
	int K;
	cin >> K;
	Bank(v1, K);
	cout << endl;
}

#include
#include
#include
using namespace std;
string matched_Prefix_Postfix(string str)
{
    if (str.length() <= 1)
    {
        return "";
    }
    string leftMax = "";
    for (int i = 1; i < str.length(); i++)
    {
        string left = str.substr(0, i);
        string right = str.substr(str.length() - i, i);
        if (left == right&&left>leftMax)
        {
            leftMax = left;
        }
    }
    return leftMax;

}
int main()
{
    int n;
    cin >> n;
    while (n--)
    {
        string s;
        cin >> s;
        string result= matched_Prefix_Postfix(s);
        if (result == "")
        {
            cout << "empty";
        }
        else
        {
            cout << result;
        }
        if (n != 0) cout << endl;
    }
}

最长重复子串

【id:55】【10分】B. DS串应用—最长重复子串
时间限制
1s
内存限制
128MB
题目描述

求串的最长重复子串长度(子串不重叠)。例如:abcaefabcabc的最长重复子串是串abca,长度为4。

输入

测试次数t

t个测试串

输出

对每个测试串,输出最长重复子串长度,若没有重复子串,输出-1.

样例查看模式
正常显示
查看格式
输入样例1 <-复制
3
abcaefabcabc
0szu0123szu1
szuabcefg

输出样例1

#include
#include
#include
using namespace std;
int findLonggest(string str)
{
    string maxStr;
    for (int i = 0; i < str.length(); i++)
    {
        for (int j = i + 1; j < str.length(); j++)
        {
            string tempStr = str.substr(i, j);
            string temp = str.substr(i+tempStr.length(), str.length());
            if (temp.find(tempStr) != str.npos&&tempStr.length()>maxStr.length())
            {
                maxStr = tempStr;
            }
            else
            {
                break;
            }
        }
    }
    return maxStr.length();
}
bool find(string str, string target)
{
    if (str.find(target) != str.npos)
    {
        return true;
    }
    return false;
}
int main()
{
    int n;
    cin >> n;
    while (n--)
    {
        string s;
        cin >> s;
        int digit=findLonggest(s);
        if (digit != 0)
        {
            cout << digit << endl;
        }
        else
        {
            cout << -1 << endl;
        }

    }
}

计算一个串的最长真前后缀

【id:54】【10分】A. 串应用- 计算一个串的最长的真前后缀
时间限制
1s
内存限制
128MB
题目描述

给定一个串,如ABCDAB,则 ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA } ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB } 因此,该串的真前缀和真后缀中最长的相等串为AB,我们称之为该串的“最长的真前后缀”。 试实现一个函数string matched_Prefix_Postfix(string str),得到输入串str的最长的真前后缀。若不存在最长的真前后缀则输出empty

输入

第1行:串的个数 n 第2行到第n+1行:n个字符串

输出

n个最长的真前后缀,若不存在最长的真前后缀则输出empty。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
6
a
ab
abc
abcd
abcda
abcdab
输出样例1
empty
empty
empty
empty
a
ab
提示

#include
#include
#include
using namespace std;
int matched_Prefix_Postfix(string str)
{
    if (str.length() <= 1)
    {
        return 0;
    }
    string leftMax = "";
    for (int i = 1; i < str.length(); i++)
    {
        string left = str.substr(0, i);
        string right = str.substr(str.length() - i, i);
        if (left == right && left > leftMax)
        {
            leftMax = left;
        }
    }
    return leftMax.length();
}
int main()
{
    int N;
    cin >> N;
    while (N--)
    {
        string s;
        cin >> s;
        int len = s.length();
        int L = len - matched_Prefix_Postfix(s);
        int count = L - matched_Prefix_Postfix(s) % L;
        if (!(len % L) && len != L)
        {
            cout<<"0";
        }else
        cout << count;
        if (N != 0) cout << endl;
    }
}

KMP算法

【id:52】【20分】E. DS串应用–KMP算法
时间限制
1s
内存限制
128MB
题目描述

学习KMP算法,给出主串和模式串,求模式串在主串的位置

算法框架如下,仅供参考

输入

第一个输入t,表示有t个实例

第二行输入第1个实例的主串,第三行输入第1个实例的模式串

以此类推

输出

第一行输出第1个实例的模式串的next值

第二行输出第1个实例的匹配位置,位置从1开始计算,如果匹配成功输出位置,匹配失败输出0

以此类推

样例查看模式
正常显示
查看格式
输入样例1 <-复制
3
qwertyuiop
tyu
aabbccdd
ccc
aaaabababac
abac

输出样例1

#include
using namespace std;
#include
class myString
{
private:
	string mainstr;
	int size;
	void GetNext(string p, int next[]);
	int KMPFind(string p, int pos, int next[]);
public:
	myString();
	~myString();
	void SetVal(string sp);
	int KMPFindSubStr(string p, int pos);
};
void myString::GetNext(string p, int next[])
{
	int i = 1;
	next[0] = -1;
	int j = -1;
	while (i < p.length())
	{
		if (j == -1 || p[i-1] == p[j])
		{
			++j;
			next[i] = j;
			i++;
		}
		else
		{
			j = next[j];
		}
	}
}
int myString::KMPFind(string p, int pos, int next[])
{
	int i = pos;
	int j = 0;
	while (i < mainstr.length() && j < int(p.length()))
	{
		if (j == -1 || mainstr[i] == p[j])
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];
		}
	}
	if (j+1 > p.length())
	{
		return i - p.length()+1;
	}
	return 0;
}
myString::myString()
{
	size = 0;
	mainstr = "";
}
myString::~myString()
{
	size = 0;
	mainstr = "";
}
void myString::SetVal(string sp)
{
	mainstr = "";
	mainstr.assign(sp);
	size = mainstr.length();
}
int myString::KMPFindSubStr(string p, int pos)
{
	int i;
	int L = p.length();
	int* next = new int[L];
	GetNext(p, next);
	for (i = 0; i < L; i++)
	{
		cout << next[i] << ' ';
	}
	cout << endl;
	int v = -1;
	v = KMPFind(p, pos, next);
	delete[]next;
	return v;

}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		string S, T;
		cin >> S >> T;
		myString str;
		str.SetVal(S);
		int index=str.KMPFindSubStr(T,0);
		cout << index << endl;
	}
}

特殊的语言

【id:152】【10分】G. 特殊的语言
时间限制
1s
内存限制
128MB
题目描述

某城邦的语言,每个字是由两个字母构成的。考古学家发现把他们的文字数字化之后,当想搜索特定的句子时,总会匹配到错误的地方。

比如一段文字是 aabcdaabcdef,想要搜索 abcd,应当搜到的是 aabcda abcd ef ,却会得到额外的一个并不符合该语言语法的结果 a abcd aabcdef(因为每个字由两个字符组成,这样匹配就把正确的“字”拆开了)。

请你帮他实现正确的匹配算法。

输入

每组数据两行,第一行为该语言的主串,第二行为模式串,都由大写或小写英文字母组成,长度都不超过 10000,且一定为偶数个。

输出

每组数据输出正确匹配的次数

样例查看模式
正常显示
查看格式
输入样例1 <-复制
abcdaabbab
ab
AbdcAbdcAbqAbdcAbdcAbp
AbdcAb
输出样例1

#include
using namespace std;
#include
#include
vector<int>v1;
class myString
{
private:
	string mainstr;
	int size;
	void GetNext(string p, int next[]);
	int KMPFind(string p, int pos, int next[]);
public:
	myString();
	~myString();
	void SetVal(string sp);
	int KMPFindSubStr(string p, int pos);
};
void myString::GetNext(string p, int next[])
{
	int i = 1;
	next[0] = -1;
	int j = -1;
	while (i < p.length())
	{
		if (j == -1 || p[i-1] == p[j])
		{
			++j;
			next[i] = j;
			i++;
		}
		else
		{
			j = next[j];
		}
	}
}
int myString::KMPFind(string p, int pos, int next[])
{
	int i = pos;
	int j = 0;
	while (i < mainstr.length() && j < int(p.length()))
	{
		if (j == -1 || mainstr[i] == p[j])
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];
		}
	}
	if (j+1 > p.length())
	{
		v1.push_back(i - p.length() + 1);
		KMPFind(p, i-p.length()+1, next);
	}
	return 0;
}
myString::myString()
{
	size = 0;
	mainstr = "";
}
myString::~myString()
{
	size = 0;
	mainstr = "";
}
void myString::SetVal(string sp)
{
	mainstr = "";
	mainstr.assign(sp);
	size = mainstr.length();
}
int myString::KMPFindSubStr(string p, int pos)
{
	int i;
	int L = p.length();
	int* next = new int[L];
	GetNext(p, next);
	int v = -1;
	v = KMPFind(p, pos, next);
	delete[]next;
	return v;
}
int main()
{
	string S, T;
	int flag = 0;
	while (cin >> S >> T)
	{
		v1.clear();
		myString str;
		str.SetVal(S);
		str.KMPFindSubStr(T,0);
		int count = 0;
		for (auto num : v1)
		{
			int left = num - 1;
			int right = S.length() - num - T.length() + 1;
			if (left % 2 == 0 && right % 2 == 0)
				count++;
		}
		if(flag++==0)
		cout << count;
		else
		{
			cout << endl << count;
		}
		
	}
}

串替换

【id:53】【20分】D. DS串应用–串替换
时间限制
1s
内存限制
128MB
题目描述

给出主串、模式串、替换串,用KMP算法找出模式串在主串的位置,然后用替换串的字符替换掉模式串

本题只考虑一处替换的情况,如果你想做的完美一些,能够实现多处替换那

可能需要考虑模式串和替换串长度不一致的情况

输入

第一个输入t,表示有t个实例

第二行输入第1个实例的主串,第三行输入第1个实例的模式串,第四行输入第1个实例的替换串

以此类推

输出

第一行输出第1个实例的主串

第二行输出第1个实例的主串替换后结果,如果没有发生替换就输出主串原来的内容。

以此类推

样例查看模式
正常显示
查看格式
输入样例1 <-复制
3
aabbccdd
bb
ff
aaabbbccc
ddd
eee
abcdef
abc
ccccc

输出样例1
aabbccdd
aaffccdd
aaabbbccc
aaabbbccc
abcdef
cccccdef

#include
using namespace std;
#include
class myString
{
private:
	string mainstr;
	int size;
	void GetNext(string p, int next[]);
	int KMPFind(string p, int pos, int next[]);
public:
	string replace(string s, int index,int len);
	myString();
	~myString();
	void SetVal(string sp);
	int KMPFindSubStr(string p, int pos);
};
string myString::replace(string s, int index,int len)
{
	string left = mainstr.substr(0, index - 1);
	string right = mainstr.substr(index + len - 1, mainstr.length());
	return left + s + right;

}
void myString::GetNext(string p, int next[])
{
	int i = 1;
	next[0] = -1;
	int j = -1;
	while (i < p.length())
	{
		if (j == -1 || p[i - 1] == p[j])
		{
			++j;
			next[i] = j;
			i++;
		}
		else
		{
			j = next[j];
		}
	}
}
int myString::KMPFind(string p, int pos, int next[])
{
	int i = pos;
	int j = 0;
	while (i < mainstr.length() && j < int(p.length()))
	{
		if (j == -1 || mainstr[i] == p[j])
		{
			++i;
			++j;
		}
		else
		{
			j = next[j];
		}
	}
	if (j + 1 > p.length())
	{
		return i - p.length() + 1;
	}
	return -1;
}
myString::myString()
{
	size = 0;
	mainstr = "";
}
myString::~myString()
{
	size = 0;
	mainstr = "";
}
void myString::SetVal(string sp)
{
	mainstr = "";
	mainstr.assign(sp);
	size = mainstr.length();
}
int myString::KMPFindSubStr(string p, int pos)
{
	int i;
	int L = p.length();
	int* next = new int[L];
	GetNext(p, next);
	int v = -1;
	v = KMPFind(p, pos, next);
	delete[]next;
	return v;

}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		string S, T, P;
		cin >> S >> T >> P;
		myString str;
		str.SetVal(S);
		int index = str.KMPFindSubStr(T, 0);
		cout << S << endl;
		if (index == -1)
		{
			cout << S;
		}
		else
		{
			string result = str.replace(P, index,T.length());
			cout << result;
		}
		cout << endl;
	}
}

二叉树构建和便利

【id:60】【20分】E. DS二叉树—二叉树构建与遍历(不含框架)
时间限制1s
内存限制128MB

题目描述

给定一颗二叉树的逻辑结构如下图,(先序遍历的结果,空树用字符‘#’表示,例如AB#C##D##),建立该二叉树的二叉链式存储结构,并输出该二叉树的先序遍历、中序遍历和后序遍历结果。

输入

第一行输入一个整数t,表示有t个二叉树

第二行起输入每个二叉树的先序遍历结果,空树用字符‘#’表示,连续输入t行。

输出

输出每个二叉树的先序遍历、中序遍历和后序遍历结果。
样例查看模式 正常显示查看格式
输入样例1 <-复制

#include
using namespace std;
#include
typedef struct BiTNode { // 结点结构
    char data;
    struct BiTNode* lchild, * rchild; // 左右孩子指针
} BiTNode, * BiTree;
int p = 0;
int flag = 0;
int CreateBiTree(BiTree& T,string s)
{
    char ch;
    ch = s[p++];
    if (ch == '#')
    {
        T = NULL;
    }
    else
    {
        T = (BiTree)malloc(sizeof(BiTNode));
        T->data = ch;
        CreateBiTree(T->lchild,s);
        CreateBiTree(T->rchild,s);
    }
    return 1;
}
void pre(BiTree& T)
{
    if (T == NULL)
    {
        return;
    }
    cout << T->data;
    pre(T->lchild);
    pre(T->rchild);
}
void inorder(BiTree& T)
{
    if (T == NULL)
    {
        return;
    }
    inorder(T->lchild);
    cout << T->data;
    inorder(T->rchild);
}
void back(BiTree& T)
{
    if (T == NULL)
    {
        return;
    }
    back(T->lchild);
    back(T->rchild);
    cout << T->data;
}
void findFather(BiTree& T,char c)
{
    if (T == NULL) return;
    if (T->lchild != NULL &&T->lchild->data==c)
    {
        flag = 1;
        findFather(T->rchild, c);
    }
    else if (T->rchild != NULL && T->rchild->data == c)
    {
        findFather(T->lchild, c);
    }
    else
    {
        findFather(T->lchild, c);
        findFather(T->rchild, c);
    }

}
vectorfind(string s)
{
    vectorv;
    for (int i = 0; i < s.length()-2; i++)
    {
        if (s[i] != '0' && s[i + 1] == '0' && s[i + 2] == '0')
        {
            v.push_back(s[i]);
        }
    }
    return v;
}
void print(vectorv)
{
    for (auto num : v)
    {
        cout << num << " ";
    }
    cout << endl;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        p = 0;
        flag = 0;
        string s;
        cin >> s;
        BiTree b;
        CreateBiTree(b, s);
        pre(b);
        cout << endl;
        inorder(b);
        cout << endl;
        back(b);
        cout << endl;
    }
    cout << endl;
}

同一颗二叉树

【id:81】【10分】B. DS二叉树–同一棵二叉树?
时间限制
1s
内存限制
128MB
题目描述

二叉树分别以数组存储方式创建、以先序遍历序列创建。输入二叉树的数组存储、先序遍历结果,判断根据它们创建的二叉树是否是同一棵二叉树。

输入

测试次数t

每组测试数据两行:

第一行:二叉树的数组存储(英文字母表示树结点,#表示空树)

第二行:二叉树的先序遍历结果(英文字母表示树结点,#表示空树)

输出

对每组测试数据,如果两种方式创建的是同一棵二叉树,输出YES,否则,输出NO。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
3
ABCDE
ABD##E##C##
ABC##DE####W##F
AB##CDW###E#F##
abc##d
ab##c#d

输出样例1
YES
YES
NO

#include
using namespace std;
#include
class TreeNode
{
public:
	char data;
	TreeNode* left;
	TreeNode* right;
	TreeNode()
	{
		left = right = NULL;
	}
};
class TreeFirst
{
public:
	int pos;
	TreeNode* root;
	string str;
	string pre;
	string in;
	TreeFirst(string str)
	{
		this->str = str;
		pre = "";
		in = "";
		pos = 0;
		root = CreateTree();
	}
	TreeNode* CreateTree()
	{
		char ch = str[pos];
		pos++;
		if (ch == '#')
		{
			return NULL;
		}
		else
		{
			TreeNode* node = new TreeNode();
			node->data = ch;
			node->left = CreateTree();
			node->right = CreateTree();
			return node;
		}
	}
	void preorder(TreeNode* T)
	{
		if (T != NULL)
		{
			pre += T->data;
			preorder(T->left);
			preorder(T->right);
		}
	}
	void inorder(TreeNode* T)
	{
		if (T != NULL)
		{
			inorder(T->left);
			in += T->data;
			inorder(T->right);
		}
	}
};
class ArrayTree
{
public:
	char* Tree;
	int number;
	string pre;
	string in;
	ArrayTree(string str)
	{
		pre = "";
		in = "";
		number = str.size();
		Tree = new char[number];
		for (int i = 0; i < number; i++)
		{
			Tree[i] = str[i];
		}
	}
	void preorder(int i)
	{
		if (i < number)
		{
			if (Tree[i] != '#')
			{
				pre += Tree[i];
				preorder(2 * i + 1);
				preorder(2 * i + 2);
			}
		}
	}
	void inorder(int i)
	{
		if (i < number)
		{
			if (Tree[i] != '#')
			{
				inorder(2 * i + 1);
				in += Tree[i];
				inorder(2 * i + 2);
			}
		}
	}
};
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		string str1, str2;
		cin >> str1 >> str2;
		if (str2[str2.size() - 1] != '#')
			str2 += "##";
		ArrayTree atree(str1);
		TreeFirst tree(str2);
		atree.inorder(0);
		atree.preorder(0);
		tree.inorder(tree.root);
		tree.preorder(tree.root);
		if (atree.pre == tree.pre && tree.in == atree.in)
		{
			cout << "YES" << endl;
		}
		else
		{
			cout << "NO\n";
		}
	}
}

赫夫曼树的构建和编码

【id:179】【20分】C. DS二叉树–赫夫曼树的构建与编码(不含代码框架)
时间限制
1s
内存限制
128MB
题目描述

给定n个权值,根据这些权值构造huffman树,并进行huffman编码

参考课本P147算法6.12 HuffmanCoding代码,注意数组访问是从位置1开始

要求:赫夫曼的构建中,默认左孩子权值不大于右孩子权值

输入

第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
依此类推

输出

逐行输出每个权值对应的编码,格式如下:权值-编码
即每行先输出1个权值,再输出一个短划线,再输出对应编码,接着下一行输入下一个权值和编码。
以此类推

样例查看模式
正常显示
查看格式
输入样例1 <-复制
1
5 15 4 4 3 2

输出样例1

#include
#include
using namespace std;
typedef struct {
	int weight;
	int parent, LChild, RChild;
}HTNode,*HuffmanTree;
typedef char** HuffmanCode;
void select(HuffmanTree& ht, int n, int& s1, int& s2)
{
	int max1 = 10000, max2 = 10000;
	for (int i = 1; i <=n; i++)
	{
		if (ht[i].parent != 0) continue;
		if (ht[i].weight < max1)
		{
			max2 = max1;
			s2 = s1;
			max1 = ht[i].weight;
			s1 = i;
		}
		else if(ht[i].weight<max2)
		{
			max2 = ht[i].weight;
			s2 = i;
		}
	}
}
HuffmanTree CreateHuffmanTree(HuffmanTree& ht, HuffmanCode& hcode, int* w, int n)
{
	int m = 2 * n - 1;
	ht = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));
	for (int i = 1; i <= n; i++)
	{
		ht[i] = { w[i],0,0,0 };
	}
	for (int i = n + 1; i <=m; i++)
	{
		ht[i] = { 0,0,0,0 };
	}
	for (int i = n + 1; i <= m; i++)
	{
		int s1=-1, s2 = -1;
		select(ht, i - 1, s1, s2);
		ht[s1].parent = i;
		ht[s2].parent = i;
		ht[i].LChild = s1;
		ht[i].RChild = s2;
		ht[i].weight = ht[s1].weight + ht[s2].weight;
	}
	hcode = (HuffmanCode)malloc((n + 1) * sizeof(char*));
	char* cd = (char*)malloc(n * sizeof(char));
	cd[n - 1] = '\0';	 
	for (int i = 1; i <= n; i++)
	{
		int start = n - 1;
		int c = -1;
		int p = -1;
		for (c = i, p = ht[i].parent; p != 0; c = p, p = ht[p].parent)
			if (ht[p].LChild == c) cd[--start] = '0';
			else cd[--start] = '1';
		hcode[i] = (char*)malloc((n - start) * sizeof(char));
		strcpy(hcode[i], &cd[start]);
	}
	free(cd);
	return ht;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		int* arr = new int[n+1];
		for (int i = 1; i <= n; i++)
		{
			cin >> arr[i];
		}
		HuffmanTree tree = NULL;
		HuffmanCode code = NULL;
		CreateHuffmanTree(tree, code, arr, n);
		for (int i = 1; i <= n; i++)
		{
			cout << arr[i] << "-" << code[i] << endl;
		}
	}
}

赫夫曼树解码

【id:180】【20分】D. DS二叉树–赫夫曼树解码(不含代码框架)
时间限制
1s
内存限制
128MB
题目描述

已知赫夫曼编码算法和程序,在此基础上进行赫夫曼解码

在赫夫曼树的类定义中增加了一个公有方法:

int  Decode(const string codestr, char txtstr[]);	//输入编码串codestr,输出解码串txtstr

该方法如果解码成功则返回1,解码失败则返回-1,本程序增加宏定义ok表示1,error表示-1

输入

第一行输入t,表示有t个测试实例
第二行先输入n,表示第1个实例有n个权值,接着输入n个权值,权值全是小于1万的正整数
第三行输入n个字母,表示与权值对应的字符
第四行输入k,表示要输入k个编码串
第五行起输入k个编码串
以此类推输入下一个示例

输出

每行输出解码后的字符串,如果解码失败直接输出字符串“error”,不要输出部分解码结果

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
5 15 4 4 3 2
A B C D E
3
11111
10100001001
00000101100
4 7 5 2 4
A B C D
3
1010000
111011
111110111

输出样例1
AAAAA
ABEAD
error
BBAAA
error
DCD

#include
#include
#include
#include
using namespace std;
#define ok 1
#define error -1
char txt[100];
class HuffNode {
public:
	int weight;
	int parent;
	int LChild;
	int RChild;
	char name;
};
class Huffman
{
public:
	int len;
	HuffNode* ht;
	string* huffcode;
	void CreateHuffmanTree(vector<int>& v1, string s);
	void select(int n, int& s1, int& s2);
	int deCode(const string codestr, char txtstr[]);
};
void Huffman::select(int n, int& s1, int& s2)
{
	int max1 = 10000, max2 = 10000;
	for (int i = 1; i <= n; i++)
	{
		if (ht[i].parent != 0) continue;
		if (ht[i].weight < max1)
		{
			max2 = max1;
			s2 = s1;
			max1 = ht[i].weight;
			s1 = i;
		}
		else if (ht[i].weight < max2)
		{
			max2 = ht[i].weight;
			s2 = i;
		}
	}
}
int Huffman::deCode(const string codestr, char txtstr[]) {
	int c = len;
	int k = 0;
	char ch;
	for (int i = 0; i < codestr.length(); i++) {

		ch = codestr[i];

		if (ch == '0') {
			//cout<
			c = ht[c].LChild;
		}
		if (ch == '1') {
			c = ht[c].RChild;
		}

		if (ch != '0' && ch != '1')
			return error;
		if (!ht[c].LChild && !ht[c].RChild) {
			txtstr[k++] = ht[c].name;
			c = len;
		}
		else {
			ch = '\0';
		}
	}
	if (ch == '\0')
		return error;
	else
		txtstr[k] = '\0';
	return ok;
}
void Huffman::CreateHuffmanTree(vector<int>& v1, string s)
{
	int n = v1.size() - 1;
	int m = 2 * n - 1;
	len = m;
	ht = (HuffNode*)malloc((m + 1) * sizeof(HuffNode));
	for (int i = 1; i <= n; i++)
	{
		ht[i] = { v1[i],0,0,0,s[i - 1] };
	}
	for (int i = n + 1; i <= m; i++)
	{
		ht[i] = { 0,0,0,0,'0' };
	}
	for (int i = n + 1; i <= m; i++)
	{
		int s1 = -1, s2 = -1;
		select(i - 1, s1, s2);
		ht[s1].parent = i;
		ht[s2].parent = i;
		ht[i].LChild = s1;
		ht[i].RChild = s2;
		ht[i].weight = ht[s1].weight + ht[s2].weight;
	}
	huffcode = new string[n + 1];
	char* cd = (char*)malloc(n * sizeof(char));
	cd[n - 1] = '\0';
	for (int i = 1; i <= n; i++)
	{
		int start = n - 1;
		int c = -1;
		int p = -1;
		for (c = i, p = ht[i].parent; p != 0; c = p, p = ht[p].parent)
			if (ht[p].LChild == c) cd[--start] = '0';
			else cd[--start] = '1';
		//huffcode[i] = (char*)malloc((n - start) * sizeof(char));
		char* arr = (char*)malloc((n - start) * sizeof(char));
		strcpy(arr, &cd[start]);
		huffcode[i] += arr;
	}
	free(cd);
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		vector<int>v(n + 1);
		v[0] = 0;
		for (int i = 1; i <= n; i++)
		{
			cin >> v[i];
		}
		string s;
		for (int i = 0; i < n; i++)
		{
			char ch;
			cin >> ch;
			s += ch;
		}
		Huffman tree;
		tree.CreateHuffmanTree(v, s);
		int count;
		cin >> count;
		while (count--)
		{
			for (int i = 0; i < 100; i++)
			{
				txt[i] = '0';
			}
			string bianma;
			cin >> bianma;
			int flag = tree.deCode(bianma, txt);
			if (flag == error)
			{
				cout << "error";///
			}
			else if (flag == ok)
			{
				for (int i = 0; i < 100; i++)
				{
					if (txt[i] != NULL)
					{
						cout << txt[i];
					}
					else
						break;
				}
			}
			cout << endl;
		}
	}
}

带权路径和

【id:71】【10分】E. DS树–带权路径和
时间限制
1s
内存限制
128MB
题目描述

计算一棵二叉树的带权路径总和,即求赫夫曼树的带权路径和。

已知一棵二叉树的叶子权值,该二叉树的带权案路径和APL等于叶子权值乘于根节点到叶子的分支数,然后求总和。如下图中,叶子都用大写字母表示,权值对应为:A-7,B-6,C-2,D-3

树的带权路径和 = 71 + 62 + 23 + 33 = 34

本题二叉树的创建参考前面的方法

输入

第一行输入一个整数t,表示有t个二叉树

第二行输入一棵二叉树的先序遍历结果,空树用字符‘0’表示,注意输入全是英文字母和0,其中大写字母表示叶子

第三行先输入n表示有n个叶子,接着输入n个数据表示n个叶子的权值,权值的顺序和前面输入的大写字母顺序对应

以此类推输入下一棵二叉树

输出

输出每一棵二叉树的带权路径和

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
xA00tB00zC00D00
4 7 6 2 3
ab0C00D00
2 10 20

#include
#include
#include
#include
using namespace std;
#define ok 1
#define error -1
class TreeNode
{
public:
	char data;
	TreeNode* left;
	TreeNode* right;
	TreeNode()
	{
		left = right = nullptr;
	}
};
class Tree
{
public:
	int pos;
	TreeNode* root;
	vector<int>v;
	string str;
	int count = 0;
	int index = 0;
	Tree(string s,vector<int>&v)
	{
		str = s;
		pos = 0;
		this->v = v;
		root = CreateTree();
	}
	TreeNode* CreateTree()
	{
		char ch = str[pos];
		pos++;
		if (ch == '0')
		{
			return NULL;
		}
		else
		{
			TreeNode* node = new TreeNode();
			node->data = ch;
			node->left = CreateTree();
			node->right = CreateTree();
			return node;
		}
	}
	void getSum(TreeNode *p,int i)
	{
		if (p == nullptr) return;
		if (p->left == nullptr && p->right == nullptr)
		{
			count += i * v[index++];
		}
		getSum(p->left, ++i);
		i--;
		getSum(p->right, ++i);
	}
	
};
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		string str;
		cin >> str;
		int n;
		cin >> n;
		vector<int>v(n);
		for (int i = 0; i < n; i++)
		{
			cin >> v[i];
		}
		Tree tree = Tree(str,v);
		tree.getSum(tree.root, 0);
		cout << tree.count << endl;
	}
}

二叉树最大路径

id:73】【10分】F. DS树–二叉树之最大路径
时间限制
1s
内存限制
128MB
题目描述

给定一颗二叉树的逻辑结构(先序遍历的结果,空树用字符‘0’表示,例如AB0C00D00),建立该二叉树的二叉链式存储结构

二叉树的每个结点都有一个权值,从根结点到每个叶子结点将形成一条路径,每条路径的权值等于路径上所有结点的权值和。编程求出二叉树的最大路径权值。如下图所示,共有4个叶子即有4条路径,

路径1权值=5 + 4 + 11 + 7 = 27 路径2权值=5 + 4 + 11 + 2 = 22

路径3权值=5 + 8 + 13 = 26 路径4权值=5 + 8 + 4 + 1 = 18

可计算出最大路径权值是27。

该树输入的先序遍历结果为ABCD00E000FG00H0I00,各结点权值为:

A-5,B-4,C-11,D-7,E-2,F-8,G-13,H-4,I-1

输入

第一行输入一个整数t,表示有t个测试数据

第二行输入一棵二叉树的先序遍历,每个结点用字母表示

第三行先输入n表示二叉树的结点数量,然后输入每个结点的权值,权值顺序与前面结点输入顺序对应

以此类推输入下一棵二叉树

输出

每行输出每棵二叉树的最大路径权值,如果最大路径权值有重复,只输出1个

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
AB0C00D00
4 5 3 2 6
ABCD00E000FG00H0I00
9 5 4 11 7 2 8 13 4 1

输出样例1

#include
#include
#include
#include
using namespace std;
#define ok 1
#define error -1
class TreeNode
{
public:
	char data;
	int digit;
	TreeNode* left;
	TreeNode* right;
	TreeNode()
	{
		left = right = nullptr;
	}
};
class Tree
{
public:
	int pos;
	TreeNode* root;
	vector<int>v;
	string str;
	int count = 0;
	int index = 0;
	int maxSum = 0;
	Tree(string s,vector<int>&v)
	{
		str = s;
		pos = 0;
		this->v = v;
		root = CreateTree();
	}
	TreeNode* CreateTree()
	{
		char ch = str[pos];
		pos++;
		if (ch == '0')
		{
			return NULL;
		}
		else
		{
			TreeNode* node = new TreeNode();
			node->data = ch;
			node->digit = v[index++];
			node->left = CreateTree();
			node->right = CreateTree();
			return node;
		}
	}
	void getMaxSum(TreeNode*node,int temp)
	{
		if (node == nullptr) return;
		temp += node->digit;
		if (node->left == nullptr && node->right == nullptr)
		{
			if (temp > maxSum) {
				maxSum = temp;
			}
		}
		getMaxSum(node->left,temp);
		getMaxSum(node->right, temp);
	}

};
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		string str;
		cin >> str;
		int n;
		cin >> n;
		vector<int>v(n);
		for (int i = 0; i < n; i++)
		{
			cin >> v[i];
		}
		Tree tree = Tree(str,v);
		tree.getMaxSum(tree.root,0);
		cout << tree.maxSum << endl;
	}
}

二叉树的中后序遍历及求叶子

【id:79】【20分】G. 二叉树的中后序遍历构建及求叶子
时间限制
1s
内存限制
128MB
题目描述

按中序遍历和后序遍历给出一棵二叉树,求这棵二叉树中叶子节点权值的最小值。

输入保证叶子节点的权值各不相同。

输入

测试数据有多组
对于每组测试数据,首先输入一个整数N (1 <= N <= 10000),代表二叉树有N个节点,接下来的一行输入这棵二叉树中序遍历的结果,最后一行输入这棵二叉树后序遍历的结果
输入一直处理到文件尾(EOF)

输出

对于每组测试数据,输出一个整数,代表二叉树中叶子节点权值最小值

样例查看模式
正常显示
查看格式
输入样例1 <-复制
7
3 2 1 4 5 7 6
3 1 2 5 6 7 4
8
7 8 11 3 5 16 12 18
8 3 11 7 16 18 12 5
1
255
255
输出样例1
1
3
255

#include
#include
#include
#include
using namespace std;
#define ok 1
#define error -1
class TreeNode
{
public:
	int digit;
	TreeNode* left;
	TreeNode* right;
	TreeNode()
	{
		left = right = nullptr;
		digit = 0;
	}
};
class Tree
{
public:
	
	TreeNode* root;
	int mid = 10000000;
	Tree(int *mid,int *last,int n)
	{	
		root = CreateTree(mid,last,n);
	}
	TreeNode* CreateTree(int *mid,int *last,int n)
	{
		if (n == 0)
		{
			return nullptr;
		}
		TreeNode* node = new TreeNode();
		node->digit = last[n - 1];
		int i = 0;
		for (i = 0; mid[i] != last[n - 1]; i++);
		node->left = CreateTree(mid,last,i);
		node->right = CreateTree(mid+i+1,last+i,n-i-1);
		return node;
	}
	void getMin(TreeNode*node)
	{
		if (node == nullptr) return;
		if (node->left == nullptr && node->right == nullptr)
		{
			if (node->digit < mid)
			{
				mid = node->digit;
			}
		}
		getMin(node->left);
		getMin(node->right);
	}

};
int main()
{
	int N;
	int flag = 0;
	while (cin >> N)
	{
		if (flag++ != 0)
		{
			cout << endl;
		}
		int* arr = new int[N];
		int* brr = new int[N];
		for (int i = 0; i < N; i++)
		{
			cin >> arr[i];
		}
		for (int i = 0; i < N; i++)
		{
			cin >> brr[i];
		}
		Tree tree(arr, brr, N);
		tree.getMin(tree.root);
		cout << tree.mid;
	}
}

二叉树镜面反转

【id:77】【20分】A. DS二叉树—二叉树镜面反转
时间限制1s
内存限制128MB

题目描述

假设二叉树用二叉链表存储,用先序序列结果创建。输入二叉树的先序序列,请你先创建二叉树,并对树做个镜面反转,再输出反转后的二叉树的先序遍历、中序遍历、后序遍历和层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。

–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求

输入

测试次数t

每组测试数据是一个二叉树的先序遍历序列,#表示空树

输出

对每棵二叉树,输出镜面反转后的先序、中序、后序和层次遍历序列。如果空树,输出四个NULL(后面不加空格)。如下:

NULL

NULL

NULL

NULL

#include
using namespace std;
class Queue
{
public:
    TreeNode* arr;
    int front;
    int maxSize = 100;
    int reaf;
    Queue()
    {
        arr = new TreeNode[maxSize];
        front = 0;
        reaf = 0;
    }
    TreeNode Getfront()
    {
        return arr[front];
    }
    void dequeue()
    {
        front++;
    }
    void enqueue(TreeNode* node)
    {
        arr[reaf++] = *node;
    }
    bool isEmpty()
    {
        if (front == reaf)
        {
            return true;
        }
        return false;
    }
};
class TreeNode
{
public:
    char data;
    TreeNode* left;
    TreeNode* right;
    TreeNode()
    {
        left = right = nullptr;
    }
};
class Tree
{
public:
    TreeNode* root;
    TreeNode* re;
    char* str;
    int pos = 0;
    Tree(char *str)
    {
        this->str = str;
        root = Create(root);
    }
    TreeNode* Create(TreeNode*p)
    {
        char ch = str[pos++];
        if(ch='\0')
        {
            return nullptr;
        }
        if (ch == '#')
        {
            return nullptr;
        }
        p = new TreeNode();
        p->data = ch;
        p->left = Create(p->left);
        p->right = Create(p->right);
        return p;
    }
    TreeNode* reverse(TreeNode* p,TreeNode*re)
    {
        if (p == nullptr)
        {
            return nullptr;
        }
        re = new TreeNode();
        re->data = p->data;
        re->left = reverse(p->right, re->left);
        re->right = reverse(p->left, re->right);
    }
    void pre(TreeNode* re)
    {
        if (re == nullptr)
        {
            return;
        }
        cout << re->data << " ";
        pre(re->left);
        pre(re->right);
    }
    void in(TreeNode* re)
    {
        if (re == nullptr)
        {
            return;
        }
        in(re->left);
        cout << re->data<<" ";
        in(re->right);
    }
    void back(TreeNode* re)
    {
        if (re == nullptr)
        {
            return;
        }
        back(re->left);
        back(re->right);
        cout << re->data<<" ";
    }
    void cengci(TreeNode* re)
    {
        Queue q;
        q.enqueue(re);
        while (!q.isEmpty())
        {
            TreeNode node = q.Getfront();
            q.dequeue();
        }
    }
};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        string s;
        char* str = new char[100];
        cin >> str;
        Tree tree = Tree(str);
       
        if (t != 0) cout << endl;
    }
}

【id:76】【20分】B. DS二叉树—二叉树结点的最大距离

题目描述

  二叉树两个结点的距离是一个结点经过双亲结点,祖先结点等中间结点到达另一个结点经过的分支数。二叉树结点的最大距离是所有结点间距离的最大值。例如,下图所示二叉树结点最大距离是3,C和D的距离。

      二叉树用先序遍历顺序创建,#表示空树。计算二叉树结点最大距离和最大距离的两个结点(假设二叉树中取最大距离的两个结点唯一)。

输入

测试次数T

第2行之后的T行,每行为一棵二叉树先序遍历结果(#表示空树)

输出

对每棵二叉树,输出树的结点最大距离和最大距离的结点,输出格式见样例。
样例查看模式 正常显示查看格式
输入样例1 <-复制
输出样例1

#include
#include
using namespace std;
class TreeNode
{
public:
    char data;
    TreeNode* left;
    TreeNode* right;
    TreeNode()
    {
        left = right = nullptr;
    }
};
class Tree
{
public:
    TreeNode* root;
    string str;
    char lnode = '0';
    char rnode = '0';
    int lm = 0;
    int pos = 0;
    int rm = 0;
    int flag = 0;
    Tree(string s)
    {
        str = s;
        root = Create(root);
    }
    TreeNode* Create(TreeNode*p)
    {
        char ch = str[pos++];
        if (ch == '#')
        {
            return nullptr;
        }
        p = new TreeNode();
        p->data = ch;
        p->left = Create(p->left);
        p->right = Create(p->right);
        return p;
    }
    void find(TreeNode* p)
    {
        if (p == nullptr)
        {
            return;
        }
        int digit = 0;
        int digit1 = 0;
        char c1 = '0', c2 = '0';
        findMax(p,0,0,p,digit,digit1,c1,c2);
        find(p->left);
        find(p->right);
    }
    void findMax(TreeNode*p,int i,int flag,TreeNode*r,int &ldigit,int &rdigit,char &lc,char &rc)
    {
        if (p == nullptr)
        {
            return;
        }
        findMax(p->left, i + 1, flag, r, ldigit,rdigit, lc,rc);
        if (p == r)
        {
            flag = 1;

        }
        if (!flag)
        {
            if (i >= ldigit)
            {
                ldigit = i;
                lc = p->data;
            }
        }
        else
        {
            if (i >= rdigit)
            {
                rdigit = i;
                rc = p->data;
            }
        }
        if (flag==1&&(ldigit + rdigit) > (lm + rm))
        {
            lm = ldigit;
            rm = rdigit;
            lnode = lc;
            rnode = rc;
        }
       
        findMax(p->right, i + 1,flag,r,ldigit,rdigit,lc,rc);
    }

};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        string s;
        cin >> s;
        Tree tree = Tree(s);
        tree.find(tree.root);
        cout << tree.lm + tree.rm << ":";
        if (tree.lnode != '0' && tree.rnode != '0')
        {
            cout << tree.lnode << " " << tree.rnode;
        }
        if (t != 0) cout << endl;
    }
}

【id:72】【10分】C. DS树–二叉树高度

题目描述

给出一棵二叉树,求它的高度。二叉树的创建采用前面实验的方法。

注意,二叉树的层数是从1开始

输入

第一行输入一个整数t,表示有t个二叉树

第二行起输入每个二叉树的先序遍历结果,空树用字符‘0’表示,连续输入t行

输出

每行输出一个二叉树的高度

样例查看模式 正常显示查看格式
输入样例1 <-复制
输出样例1

#include
#include
using namespace std;
class TreeNode
{
public:
    char data;
    TreeNode* left;
    TreeNode* right;
    TreeNode()
    {
        left = right = nullptr;
    }
};
class Tree
{
public:
    TreeNode* root;
    string str;
    int pos = 0;
    int max = 0;
    Tree(string s)
    {
        str = s;
        root = Create(root);
    }
    TreeNode* Create(TreeNode*p)
    {
        char ch = str[pos++];
        if (ch == '0')
        {
            return nullptr;
        }
        p = new TreeNode();
        p->data = ch;
        p->left = Create(p->left);
        p->right = Create(p->right);
        return p;
    }
    void findMax(TreeNode*p,int i)
    {
        if (p == nullptr)
        {
            return;
        }
        if (i > max)
        {
            max = i;
        }
        findMax(p->left, i + 1);
        findMax(p->right, i + 1);
    }

};

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        string s;
        cin >> s;
        Tree tree = Tree(s);
        tree.findMax(tree.root,1);
        cout << tree.max << endl;
    }
}

完全二叉树的根

【id:169】【10分】D. 完全二叉树的根
时间限制
10s
内存限制
128MB
题目描述

有一棵n个节点的完全二叉树,存储着 1~n 的值。

有n(n-1)(n-2)条关于这颗树的信息,每条信息,由一个四元组组成(i,j,k,0/1)(i≠j≠k),均不完全一样。

若四元组最后一个元素为0,表示值为k的这个节点不是值为 i 的结点和值为 j 的结点的最近公共祖先,

若四元组最后一个元素为1,则反之。

基于给出的信息,求根结点的值。

输入

一行一个整数n (3 ≤ n ≤ 8)

接下来n(n-1)(n-2)行,每行四个整数表示四元组(i,j,k,0/1)(i≠j≠k)

输出

一行一个整数,表示树根节点的值

#include
#include
using namespace std;
class node
{
public:
	int i, j, k, flag;
	node(int i, int j, int k, int flag)
	{
		this->i = i;
		this->j = j;
		this->k = k;
		this->flag = flag;
	}
	node()
	{

	}
};
int main()
{
	int n;
	int i=-1, j=-1, k=-1, flag = -1;
	cin >> n;
	vector<int>v2(n+1,0);
	vector<node>v;
	for (int p = 0; p < n*(n-1)*(n-2); p++)
	{
		cin >> i >> j >> k >> flag;
		node nodeTemp = node(i, j, k, flag);
		v.push_back(nodeTemp);
	}
	for (auto vNode : v)
	{
		if (vNode.flag == 1)
		{
			v2[vNode.k]++;
		}
	}
	int max = 0;
	int index = -1;
	for (int i = 1; i < v2.size(); i++)
	{
		if (v2[i] > max)
		{
			max = v2[i];
			index = i;
		}
	}
	cout << index;

}

】【20分】E. 图综合练习–构建邻接表

题目描述

已知一有向图,构建该图对应的邻接表。

邻接表包含数组和单链表两种数据结构,其中每个数组元素也是单链表的头结点,数组元素包含两个属性,属性一是顶点编号info,属性二是指针域next指向与它相连的顶点信息。

单链表的每个结点也包含两个属性,属性一是顶点在数组的位置下标,属性二是指针域next指向下一个结点。

输入

第1行输入整数t,表示有t个图

第2行输入n和k,表示该图有n个顶点和k条弧。

第3行输入n个顶点。

第4行起输入k条弧的起点和终点,连续输入k行

以此类推输入下一个图

输出

输出每个图的邻接表,每行输出格式:数组下标 顶点编号-连接顶点下标-…-^,数组下标从0开始。

具体格式请参考样例数据,每行最后加入“^”表示NULL。

样例查看模式
正常显示
查看格式

#include
#include
using namespace std;
class nodeList
{
public:
	int digit;
	nodeList* next;
	nodeList()
	{
		digit = -1;
		next = nullptr;
	}
};
class nodeArray
{
public:
	char info;
	nodeList* next;
};
class Array
{
public:
	vector<nodeArray*>v;
	void ArrayInit(vector<char>v1);
	void print();
	int findIndex(char c)
	{
		for (int i = 0; i < v.size(); i++)
		{
			if (v[i]->info == c)
			{
				return i;
			}
		}
		return -1;
	}
	void setFu(vector<pair<char, char>>v2)
	{
		for (int i = 0; i < v2.size(); i++)
		{
			int index = findIndex(v2[i].first);
			int index2 = findIndex(v2[i].second);
			nodeList* node = new nodeList();
			node->digit = index2;
			node->next = nullptr;
			if(v[index]->next==nullptr)
				v[index]->next = node;
			else
			{
				nodeList* temp = v[index]->next;
				while (temp->next != nullptr)
				{
					temp = temp->next;
				}
				temp->next = node;
			}
		}
	}
};
void Array::ArrayInit(vector<char>v1)
{
	for (int i = 0; i < v1.size(); i++)
	{
		nodeArray* node = new nodeArray();
		node->info = v1[i];
		node->next = nullptr;
		v.push_back(node);
	}
}
void Array::print()
{
	for (int i = 0; i < v.size(); i++)
	{
		cout << i << " "<<v[i]->info;
		nodeList* p = v[i]->next;
		while (p!=nullptr)
		{
			cout << "-" << p->digit;
			p = p->next;
		}
		cout << "-" << '^' << endl;
	}
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, k;
		cin >> n >> k;
		vector<char>v(n,0);
		for (int i = 0; i < n; i++)
		{
			cin >> v[i];
		}
		vector<pair<char, char>>v1;
		for (int i = 0; i < k; i++)
		{
			char c1, c2;
			cin >> c1 >> c2;
			v1.push_back(make_pair(c1, c2));
		}
		Array array;
		array.ArrayInit(v);
		array.setFu(v1);
		array.print();
	}
}

【id:93】【20分】F. DS图—图的邻接矩阵存储及度计算

题目描述

假设图用邻接矩阵存储。输入图的顶点信息和边信息,完成邻接矩阵的设置,并计算各顶点的入度、出度和度,并输出图中的孤立点(度为0的顶点)

–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求

输入

测试次数T,每组测试数据格式如下:

图类型 顶点数 (D—有向图,U—无向图)

顶点信息

边数

每行一条边(顶点1 顶点2)或弧(弧尾 弧头)信息

输出

每组测试数据输出如下信息(具体输出格式见样例):

图的邻接矩阵

按顶点信息输出各顶点的度(无向图)或各顶点的出度 入度 度(有向图)。孤立点的度信息不输出。

图的孤立点。若没有孤立点,不输出任何信息。

样例查看模式
正常显示
查看格式
输入样例1 <-复制
2
D 5
V1 V2 V3 V4 V5
7
V1 V2
V1 V4
V2 V3
V3 V1
V3 V5
V4 V3
V4 V5
U 5
A B C D E
5
A B
A C
B D
D C
A D
输出样例1

#include
#include
using namespace std;
class Graph
{
public:
	int** mat;
	string* name;
	char type;
	int du[20][2];
	int n;
	Graph(char type, int n,string*str)
	{
		this->type = type;
		this->n = n;
		name = str;
	}
	int findIndex(string c)
	{
		for (int i = 0; i < n; i++)
		{
			if (name[i] == c)
			{
				return i;
			}
		}
		return -1;
	}
	void GraphInit(string **str,int count)
	{
		mat = new int* [n];
		for (int i = 0; i < n; i++)
		{
			mat[i] = new int[n];
		}
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				mat[i][j] = 0;
			}
		}
		if (type == 'D')
		{
			for (int i = 0; i < count; i++)
			{
				string c1 = str[i][0];
				string c2 = str[i][1];
				int index1 = findIndex(c1);
				int index2 = findIndex(c2);
				mat[index1][index2]++;
			}
		}
		else if (type == 'U')
		{
			for (int i = 0; i < count; i++)
			{
				string c1 = str[i][0];
				string c2 = str[i][1];
				int index1 = findIndex(c1);
				int index2 = findIndex(c2);
				mat[index1][index2]++;
				mat[index2][index1]++;
			}
		}
	}
	int getChu(int tarI)
	{
		int sum = 0;
		for (int j = 0; j < n; j++)
		{
			sum += mat[tarI][j];
		}
		return sum;
	}
	int getRu(int tarJ)
	{
		int sum = 0;
		for (int i = 0; i < n; i++)
		{
			sum += mat[i][tarJ];
		}
		return sum;
	}
	void print()
	{
		for (int i = 0; i < n; i++)
		{
			int flag = 0;
			for (int j = 0; j < n; j++)
			{
				if (flag++ == 0)
					cout << mat[i][j];
				else
					cout << " " << mat[i][j];
			}
			cout << endl;
		}
		int gu = -1;
		if (type == 'D')
		{
			for (int i = 0; i < n; i++)
			{
				int chu = getChu(i);
				int ru = getRu(i);
				if (chu + ru == 0)
				{
					gu = i;
					continue;
				}
				cout << name[i] << ":";
				cout << " " << chu << " " << ru << " " << chu + ru << endl;
			}
		}
		else if (type == 'U')
		{
			for (int i = 0; i < n; i++)
			{
				int chu = getChu(i);
				if (chu == 0)
				{
					gu = i;
					continue;
				}
				cout << name[i] << ":";
				cout << " " << chu <<endl;
			}
		}
		if (gu != -1)
		{
			cout << name[gu];
		}

	}

};
int main()
{
	int T;
	cin >> T;
	while (T--)
	{
		char type;
		cin >> type;
		int n;
		cin >> n;
		string* str = new string[n];
		for (int i = 0; i < n; i++)
		{
			cin >> str[i];
		}
		int count;
		cin >> count;
		string**bian= new string*[count];
		for (int i = 0; i < count; i++)
		{
			bian[i] = new string[2];
		}
		for (int i = 0; i < count; i++)
		{
			for (int j = 0; j < 2; j++)
			{
				cin >> bian[i][j];
			}
		}
		Graph g = Graph(type, n, str);
		g.GraphInit(bian, count);
		g.print();
		//if (T != 0) cout << endl;
	}
}

图深度优先搜索

【id:87】【10分】A. DS图遍历–深度优先搜索
时间限制1s
内存限制128MB

题目描述

给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始

注意:图n个顶点编号从0到n-1

代码框架如下:

输入

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

以此类推输入下一个示例

输出

#include
using namespace std;
const int MaxLen = 20;
class Map
{
private:
    bool Visit[MaxLen];
    int Matrix[MaxLen][MaxLen];
    int Vexnum;
    void DFS(int v);
public:
    void SetMatrix(int vnum, int mx[MaxLen][MaxLen]);
    void DFSTraverse();
};
void Map::SetMatrix(int vnum, int mx[MaxLen][MaxLen])
{
    int i, j;
    Vexnum = vnum;
    for (i = 0; i < MaxLen; i++)
    {
        for (j = 0; j < MaxLen; j++)
        {
            Matrix[i][j] = 0;
        }
    }
    for (i = 0; i < Vexnum; i++)
    {
        for (j = 0; j < Vexnum; j++)
        {
            Matrix[i][j] = mx[i][j];
        }
    }
}
void Map::DFSTraverse()
{
    for (int i = 0; i < MaxLen; i++)
    {
        Visit[i] = false;
    }
    for (int i = 0; i < Vexnum; i++)
    {
        if (Visit[i] == false)
        {
            DFS(i);
        }
    }
    cout << endl;
}
void Map::DFS(int v)
{
    int w, i, k;
    Visit[v] = true;
    cout << v << " ";
    int* AdjVex = new int[MaxLen];
    for (int i = 0; i < MaxLen; i++)
        AdjVex[i] = -1;
    k = 0;
    for (int j = 0; j < Vexnum; j++)
    {
        if (Matrix[v][j] == 1)
        {
            AdjVex[k++] = j;
        }
    }
    i = 0;
    for (w = AdjVex[i]; w != -1; w = AdjVex[++i])
    {
        if (Visit[w] == false)
        {
            DFS(w);
        }
    }
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int mx[MaxLen][MaxLen];
        for (int i = 0; i < MaxLen; i++)
        {
            for (int j = 0; j < MaxLen; j++)
            {
                mx[i][j] = 0;
            }
        }
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cin >> mx[i][j];
            }
        }
        Map map;
        map.SetMatrix(n, mx);
        map.DFSTraverse();
    }
}

【id:88】【10分】B. DS图遍历–广度优先搜索

题目描述

给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始

注意:图n个顶点编号从0到n-1

代码框架如下:

输入

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

以此类推输入下一个示例

输出

每行输出一个图的广度优先搜索结果,结点编号之间用空格隔开

#include
#include
using namespace std;
const int MaxLen = 20;
class Map
{
private:
    bool Visit[MaxLen];
    int Matrix[MaxLen][MaxLen];
    int Vexnum;
    void BFS(int v);
public:
    void SetMatrix(int vnum, int mx[MaxLen][MaxLen]);
    void BFSTraverse();
};
void Map::SetMatrix(int vnum, int mx[MaxLen][MaxLen])
{
    int i, j;
    Vexnum = vnum;
    for (i = 0; i < MaxLen; i++)
    {
        for (j = 0; j < MaxLen; j++)
        {
            Matrix[i][j] = 0;
        }
    }
    for (i = 0; i < Vexnum; i++)
    {
        for (j = 0; j < Vexnum; j++)
        {
            Matrix[i][j] = mx[i][j];
        }
    }
}
void Map::BFSTraverse()
{
    BFS(0);
}
void Map::BFS(int v)
{
    int w, i, k;
    int* AdjVex = new int[Vexnum];
    for (i = 0; i < Vexnum; i++)
        Visit[i] = false;
    queue<int>q;
    for (v = 0; v < Vexnum; v++)
    {
        if (!Visit[v])
        {
            q.push(v);
        }
        while (!q.empty())
        {
            int u = q.front();
            q.pop();
            if(Visit[u]==false)
            cout << u << " ";
            Visit[u] = true;
            i = 0;
            k = 0;
            for (w = 0; w < Vexnum; w++)
            {
                if (Matrix[u][w] == 1&&u!=w)
                {
                    AdjVex[k++] = w;
                }
            }
            for (i = 0; i < k; i++)
            {
                if (!Visit[AdjVex[i]])
                {
                    q.push(AdjVex[i]);
                }
            }
        }
    }
    cout << endl;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int mx[MaxLen][MaxLen];
        for (int i = 0; i < MaxLen; i++)
        {
            for (int j = 0; j < MaxLen; j++)
            {
                mx[i][j] = 0;
            }
        }
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cin >> mx[i][j];
            }
        }
        Map map;
        map.SetMatrix(n, mx);
        map.BFSTraverse();
    }
}

【id:90】【10分】E. 图的应用之——图的连通

题目描述

给定一个图的邻接矩阵,请判断该图是否是连通图。连通图:任意两个顶点之间都有路径。
–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求

输入

第1行输入一个整数k,表示有k个测试数据
第2行输入一个整数n,表示有n个结点
从第3行起到第n+2行输入一个邻接矩阵,其中Matrix[i,j]=1表示第i,j个结点之间有边,否则不存在边。
接下来是第2到第k个测试数据的结点数和邻接矩阵

输出

输出Yes or No表示图是否是强连通图

#include
#include
#include
using namespace std;
const int MaxLen = 20;
class Map
{
private:
    bool Visit[MaxLen];
    int Matrix[MaxLen][MaxLen];
    int Vexnum;
    int bian[MaxLen][MaxLen];
public:
    void SetMatrix(int vnum, int mx[MaxLen][MaxLen]);
    void SetBian();
    bool check();
};
bool Map::check()
{
    /*for (int i = 0; i < Vexnum; i++)
    {
        for (int j = 0; j < Vexnum; j++)
        {
            if (bian[i][j] == 0 && i != j)
                return false;
        }
    }
    return true;*/
    for (int i = 0; i < Vexnum - 1; i++)
    {
        if (Matrix[i][i + 1] != 1)
            return false;
    }
    if (Matrix[Vexnum - 1][0] == 1)
        return true;
    for (int i = 0; i < Vexnum-1; i++)
    {
        if (Matrix[i + 1][i] != 1)
            return false;
    }
    return true;
}
void Map::SetBian()
{
    for (int i = 0; i < Vexnum; i++)
    {
        for (int j = 0; j < Vexnum; j++)
        {
            bian[i][j] = 0;
        }
    }

    for (int i = 0; i < Vexnum; i++)
    {
        for (int j = 0; j < Vexnum; j++)
        {
            if (Matrix[i][j] == 1)
            {
                bian[i][j] = 1;
                bian[j][i] = 1;
            }
        }
    }
}
void Map::SetMatrix(int vnum, int mx[MaxLen][MaxLen])
{
    int i, j;
    Vexnum = vnum;
    for (i = 0; i < MaxLen; i++)
    {
        for (j = 0; j < MaxLen; j++)
        {
            Matrix[i][j] = 0;
        }
    }
    for (i = 0; i < Vexnum; i++)
    {
        for (j = 0; j < Vexnum; j++)
        {
            Matrix[i][j] = mx[i][j];
        }
    }
}
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int mx[MaxLen][MaxLen];
        for (int i = 0; i < MaxLen; i++)
        {
            for (int j = 0; j < MaxLen; j++)
            {
                mx[i][j] = 0;
            }
        }
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                cin >> mx[i][j];
            }
        }
        Map map;
        map.SetMatrix(n, mx);
        bool flag = map.check();
        if (flag)
            cout << "Yes\n";
        else
            cout << "No\n";
    }
}

最小生成树

id:94】【20分】G. DS图—最小生成树
时间限制
1s
内存限制
128MB
题目描述

根据输入创建无向网。分别用Prim算法和Kruskal算法构建最小生成树。(假设:输入数据的最小生成树唯一。)

输入

顶点数n

n个顶点

边数m

m条边信息,格式为:顶点1 顶点2 权值

Prim算法的起点v

输出

输出最小生成树的权值之和

对两种算法,按树的生长顺序,输出边信息(Kruskal中边顶点按数组序号升序输出)

#include 
#include 
#include 
using namespace std;

class Graph{
    int vexNum;
    int arcNum;
    int **array;
    string *vex;
    bool *visit;
    int Index(string str);
    bool isOver();
public:
    Graph();
    ~Graph();
    void Prim(string Vex);
    void Kruskal();
};

Graph::Graph(){
    cin>>vexNum;
    vex = new string[vexNum];
    for(int i=0;i<vexNum;i++)
        cin>>vex[i];

    array = new int*[vexNum];
    visit = new bool[vexNum];
    for(int i=0;i<vexNum;i++)
    {
        visit[i] = false;
        array[i] = new int[vexNum];
        for(int j=0;j<vexNum;j++)
            array[i][j] = 99999;
    }

    cin>>arcNum;
    for(int i=0;i<arcNum;i++)
    {
        string str1,str2;
        int weight;
        cin>>str1>>str2>>weight;
        int num1=Index(str1),num2=Index(str2);
        array[num1][num2] = weight;
        array[num2][num1] = weight;
    }

}

Graph::~Graph() {

}

int Graph::Index(string str) {
    for(int i=0;i<vexNum;i++)
        if(vex[i]==str)
            return i;
    return -1;
}

void Graph::Prim(string Vex) {
    int v = Index(Vex);
    visit[v] = true;
    int minWeight=0;
    queue<string> start;
    queue<string> end;
    queue<int> weights;
    while (!isOver())
    {
        int min=99999,startVex=-1,endVex=-1;
        for(int i=0;i<vexNum;i++)
        {
            if(visit[i])
            {
                for(int j=0;j<vexNum;j++)
                {
                    if(!visit[j] && array[i][j]<min) {
                        min = array[i][j];
                        startVex = i;
                        endVex = j;
                    }
                }
            }
        }
        visit[endVex] = true;
        minWeight+=min;
        start.push(vex[startVex]);
        end.push(vex[endVex]);
        weights.push(min);
    }

    cout<<minWeight<<endl;
    cout<<"prim:"<<endl;
    while (!start.empty())
    {
        cout<<start.front()<<' '<<end.front()<<' '<<weights.front()<<endl;
        start.pop();
        end.pop();
        weights.pop();
    }
}

bool Graph::isOver() {
    for(int i=0;i<vexNum;i++)
        if(!visit[i])
            return false;
    return true;
}

void Graph::Kruskal() {
    cout<<"kruskal:"<<endl;
    int father[vexNum]; //每个点的阵营
    for(int i=0;i<vexNum;i++)
        father[i] = i;
    bool isExist[vexNum][vexNum];
    for(int i=0;i<vexNum;i++)
        for(int j=0;j<vexNum;j++)
            isExist[i][j]= false;

    for(int k=0;k<vexNum-1;k++) //vexNum个结点,有vexNum-1条边
    {
        //找最小权值边
        int min=99999,pos1=0,pos2=0;
        for(int i=0;i<vexNum;i++)
        {
            for(int j=0;j<vexNum;j++)
            {
                if(father[i] == father[j])     //如果同一阵营,则不找其边,防止构成环
                    continue;

                if(array[i][j]<min && !isExist[i][j])
                {
                    min = array[i][j];
                    pos1 = i;
                    pos2 = j;
                }
            }
        }

        isExist[pos1][pos2] = true;
        isExist[pos2][pos1] = true;
        //编入阵营
        if(pos1<pos2)
        {
            cout<<vex[pos1]<<' '<<vex[pos2]<<' '<<min<<endl;
            for(int i=0;i<vexNum;i++)
                if(father[i] == father[pos2] && i!=pos2)
                    father[i] = father[pos1];
            father[pos2] = father[pos1];
        }
        else
        {
            cout<<vex[pos2]<<' '<<vex[pos1]<<' '<<min<<endl;
            for(int i=0;i<vexNum;i++)
                if(father[i] == father[pos1] && i!=pos1)
                    father[i] = father[pos2];
            father[pos1] = father[pos2];
        }
    }
}

int main()
{
    Graph myGraph;
    string v;
    cin>>v;
    myGraph.Prim(v);
    myGraph.Kruskal();
    return 0;
}


}

. 货币套汇(图路径)

【id:98】【20分】A. 货币套汇(图路径)
时间限制1s
内存限制128MB

题目描述

套汇是指利用货币汇兑率的差异将一个单位的某种货币转换为大于一个单位的同种货币。例如,假定1 美元可以买0.7 英镑,1 英镑可以买9.5 法郎,1法郎可以买到0.16美元。通过货币兑换,一个商人可以从1 美元开始买入,得到0.7×9.5×0.16=1.064美元,从而获得6.4%的利润。 给定n种货币c1 ,c2 ,… ,cn的有关兑换率,试设计一个有效算法,确定货币间是否存在套汇的可能性。

提示:判断图上是否出现正环,即环上所有的边相乘大于1

输入

第一行:测试数据组数

每组测试数据格式为:

第一行:正整数n (1< =n< =30),正整数m,分别表示n种货币和m种不同的货币兑换率。

2~n+1行,n种货币的名称。

n+2~n+m+1行,每行有3 个数据项ci,rij 和cj ,表示货币ci 和cj的兑换率为 rij。

输出

对每组测试数据,如果存在套汇的可能则输出YES

如果不存在套汇的可能,则输出NO。
样例查看模式 正常显示查看格式

#include
#include
#define N 30
using namespace std;
class Graph
{
public:
    int vexnum;
    string v[N];
    map<pair<string,string>,double> bian;
    Graph(int n,int m)
    {
        vexnum = n;
        for (int i = 0; i < N; i++)
        {
            v[i] = "";
        }
        for (int i = 0; i < n; i++)
        {
            cin >> v[i];
        }
        string p1, p2;
        double value;
        for (int i = 0; i < m; i++)
        {
            cin >> p1 >> value >> p2;
            bian.emplace(make_pair(p1, p2), value);
        }
    }
    bool check()
    {
        for (int i = 0; i < vexnum; i++)
        {
            double sum = 1;
            string item = v[i];
            string item2 = v[i];
            int j;
            string last = "";
            for (int k = i+1; k < vexnum; k++)
            {
                pair<string, string>p = make_pair(item,v[k]);
                pair<string, string>p2 = make_pair(v[k],item);
                if (bian.find(p) != bian.end() && bian.find(p2) != bian.end() && bian.at(p) * bian.at(p2) > 1)
                {
                    return true;
                }
            }
            do
            {
                int count = 0;
                for (j = i; count<vexnum; j++,count++)
                {
                    pair<string, string>p = make_pair(item, v[j%vexnum]);
                    if (bian.find(p) != bian.end()&&p.second!=last)
                    {
                        last = item;
                        item = v[j];
                        sum *= bian.at(p);
                        break;
                    }
                    if (j == vexnum)
                        break;
                }
                if (j == vexnum)
                {
                    break;
                }
            } while (item != v[i]);
            if (j == vexnum)
                continue;
            if (sum > 1)
                return true;
        }
        return false;
    }
};
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n, m;
        cin >> n >> m;
        Graph graph(n,m);
        if (graph.check())
            cout << "YES";
        else
            cout << "NO";
        if (t != 0) cout << endl;
    }
}

id:104】【10分】C. 拓扑排序-STL版

id:104】【10分】C. 拓扑排序-STL版
时间限制1s
内存限制128MB

题目描述

已知有向图,顶点从0开始编号,求它的求拓扑有序序列。

拓扑排序算法:给出有向图邻接矩阵
1.逐列扫描矩阵,找出入度为0且编号最小的顶点v

2.输出v,并标识v已访问

3.把矩阵第v行全清0

重复上述步骤,直到所有顶点输出为止

/
// STL::vector基本用法
1)
vector::push_back(1); //将1增加到数组尾部
vector::push_back(e); //将类型为E的一个对象e增加到数组尾部.其中类型E可以自行定义,如Vertex类,int类等。
2.1)
vector vec;
int x = vec[1]; //读取组数v(索引从0开始)的第1个元素
2.2)
vector v;
int& x = v[1]; //引用组数v的第1个元素,注意此处的引用&的用法
x = 10; //修改组数v的第1个元素为10

vector adjMat; //声明一个矩阵对象adjMat
vector row; //声明一个vector(动态数组)对象row表示矩阵的一行
int j=0;
for(; j int edge;
cin >> edge;
row.push_back(edge); //将边信息增加到数组row的最后
}

this->adjMat.push_back(row); //将row增加到数组adjMat的最后

//

// 参考代码框架

#include
#include
using namespace std;
class Graph {
public:
vector isFinished; //索引号所指示的顶点是否已处理过
vector adjMat; //邻接矩阵
int n; //顶点数 as 成员变量
public:
void readAdjMatrix() {
//从输入读入邻接矩阵,存入this->adjMat
cin >> this->n; //顶点数
int i=0;
for(; i //TODO:设置this->isFinished数组:每个顶点未曾访问过
//提示:调用vector::push_back方法
vector row;
int j=0;
for(; j int edge;
cin >> edge; //读入顶点对i,j之间是否有一条边
//TODO:将边信息增加入row
}
//TODO:将row增加入this->adjMat
//提示:以row为参数,调用adjMat的push_back方法
}
}
bool isZeroInDegrees(int vertexNo) {
//判定顶点vertexNo是否没有入度
int i=0;
//this->adjMat[i][vertexNo] == 0
//表示顶点i与vertexNo之间没有边相连
for(; iadjMat[i][vertexNo] == 0; ++i);
//TODO:返回true if 顶点vertexNo没有入度; false [otherwise]
}
int select() {
//从所有顶点中,选出一个顶点i,满足:
//1) i没有处理过,即isFinished[i]=false
//2) i的入度为0
int i = 0;
for (; i < n; ++i) {
//TODO:若顶点i的已经处理过,则pass
//TODO:若顶点度>0,则pass
//提示:调用isZeroInDegrees
//TODO: 设置顶点i已经处理过,即isFinished[i]为正确值
//TODO: 返回i
}
//TODO: 返回-1, 表示未找到满足1)+2)条件的顶点
}
void update(int rootNo) {
//更新顶点rootNo的出弧,即将顶点rootNo从图中断开
int j=0;
for(;j //TODO: 设置adjMat[rootNo][j]为0
}
}
/
// 拓扑排序主算法
void topologySort() {
int i=0;
for(; i int root; // 声明顶点索引号(编号)用于存放本次选出的顶点
//TODO: 调用select方法,并将其返回值存入root
//TODO: 若root=-1,则break;
// root=-1表示没有可以排出的顶点
//TODO: 以root为参数,调用update方法
//TODO:输出当前选出的顶点root 和一个空格
}
//TODO:输出一行
}
void main() {
readAdjMatrix();
topologySort();
}
};
int main() {
int t;
cin >> t;
while (t–) {
Graph g;
g.main();
}
return 0;
}

输入

第一行输入一个整数t,表示有t个有向图

第二行输入n,表示图有n个顶点

第三行起,输入n行整数,表示图对应的邻接矩阵

以此类推输入下一个图的顶点数和邻接矩阵

输出

每行输出一个图的拓扑有序序列

#include 
#include 
using namespace std;
class Graph {
public:
    vector<bool> isFinished;      //索引号所指示的顶点是否已处理过
    vector<vector<int> > adjMat;  //邻接矩阵
    int n;                        //顶点数 as 成员变量
public:
    void readAdjMatrix() {
        //从输入读入邻接矩阵,存入this->adjMat
        cin >> this->n;           //顶点数
        int i = 0;
        for (; i < n; ++i) {
            //TODO:设置this->isFinished数组:每个顶点未曾访问过
            //提示:调用vector::push_back方法
            isFinished.push_back(false);
            vector<int> row;
            int j = 0;
            for (; j < n; ++j) {
                int edge;
                cin >> edge;    //读入顶点对i,j之间是否有一条边
                //TODO:将边信息增加入row
                row.push_back(edge);
            }
            adjMat.push_back(row);
            //TODO:将row增加入this->adjMat
            //提示:以row为参数,调用adjMat的push_back方法
        }
    }
    bool isZeroInDegrees(int vertexNo) {
        //判定顶点vertexNo是否没有入度
        int i = 0;
        //this->adjMat[i][vertexNo] == 0
        //表示顶点i与vertexNo之间没有边相连
        for (; i < n && this->adjMat[i][vertexNo] == 0; ++i);
        //TODO:返回true if 顶点vertexNo没有入度; false [otherwise]
        if (i == n)
            return true;
        return false;
    }
    int select() {
        //从所有顶点中,选出一个顶点i,满足:
        //1) i没有处理过,即isFinished[i]=false
        //2) i的入度为0
        int i = 0;
        for (; i < n; ++i) {
            if (isFinished[i])
                continue;
            if (!isZeroInDegrees(i))
                continue;
            return i;
            //TODO:若顶点i的已经处理过,则pass
            //TODO:若顶点度>0,则pass
            //提示:调用isZeroInDegrees
            //TODO: 设置顶点i已经处理过,即isFinished[i]为正确值
            //TODO: 返回i
        }
        return -1;
        //TODO: 返回-1, 表示未找到满足1)+2)条件的顶点
    }
    void update(int rootNo) {
        //更新顶点rootNo的出弧,即将顶点rootNo从图中断开
        int j = 0;
        for (; j < n; ++j) {
            //TODO: 设置adjMat[rootNo][j]为0
            adjMat[rootNo][j] = 0;
        }
    }
    /
    // 拓扑排序主算法
    void topologySort() {
        int i = 0;
        for (; i < n; ++i) {  //遍历n次:即按拓扑序,依次选择(排出)n个顶点
            int root;  
            root = select();
            if (root == -1) break;
            update(root);
            isFinished[root] = true;
            cout << root << " ";
            
            
            // 声明顶点索引号(编号)用于存放本次选出的顶点
            //TODO: 调用select方法,并将其返回值存入root
            //TODO: 若root=-1,则break;
            // root=-1表示没有可以排出的顶点
            //TODO: 以root为参数,调用update方法
            //TODO:输出当前选出的顶点root 和一个空格
        }
        //TODO:输出一行
    }
    void main() {
        readAdjMatrix();
        topologySort();
    }
};
int main() {
    int t;
    cin >> t;
    while (t--) {
        Graph g;
        g.main();
        if (t != 0) cout << endl;
    }
    return 0;
}

【id:95】【20分】D. DS图—图的最短路径(不含代码框架)

题目描述

给出一个图的邻接矩阵,输入顶点v,用迪杰斯特拉算法求顶点v到其它顶点的最短路径。

/

基本STL的用法:

class Vertex {
public:
int indexNo;
string label;
int distance;
bool isVisited;
};
void foo() {
vector v;
Vertex& x = v[1]; //引用组数v的第1个元素,注意此处的引用&的用法
x.isVisited = 10; //修改组数v的第1个元素的isVisited属性值=10
x.label = “V0”; //修改组数v的第1个元素的label属性值=“V0”
}

/
// 代码框架
#include
#include
#include
using namespace std;

//定义无穷大距离
#define MAX_DIS 0x7FFFFF

class Vertex {
public:
int indexNo; //顶点索引号:顶点位于顶点数组的下标取值[0,n)
string label; //顶点的标签
int distance; //顶点到源点的距离
bool isVisited; //顶点是否已经按Dijkstra算法处理过(不用再处理了)
vector path; //顶点到源点的路径

Vertex(int indexNo, const string& label="", int distance=MAX_DIS) {
    this->label = label;
    this->distance = distance;

    this->indexNo = indexNo;
    this->isVisited = false;
}
void updatePath(const vector& prePath) {
    this->path = prePath;   //复制源结点到前一个结点的路径
                            //TODO: 增加本结点到路径数组this->path中
}

//打印输出本结点信息
//输入:顶点数组(供查询用)、源结点索引号(顶点数组下标)
void displayPath(vector& vertexes, int sourceNo) {

    //0-1-5----[0 1 ]
    cout << vertexes[sourceNo].label; //0
    cout << "-";
    cout << this->label; //1

    cout << "-";
    if (this->distance >= MAX_DIS) {
                                //TODO: 如果源结点到本结点距离无穷大,则(按题目要求)输出-1
        return;
    }
    cout << this->distance; //5
    cout << "----";

    cout << "[";
    int i=0;
    int size = this->path.size();
    for(; i

};

//打印顶点信息,供调试用
ostream& operator<<(ostream& out, const Vertex& v) {
out << v.indexNo << “_” << v.label << ": " << v.distance << " ";
return out;
}

/
class Graph {
public:
vector vertexes; //顶点数组:存放顶点信息
vector adjMat; //邻接矩阵:存放每对结点距离,若1对结点i,j之间无边相连,则adjMat[i,j]=0
public:

void printVertexes() {  //用于调试
    int i=0;
    int n = vertexes.size();
    for(; i> n;

    int indexNo=0;
    for(; indexNovertexes.push_back(v);  //把v加入顶点数组
    }

}
void readAdjMat() {
//读取距离矩阵,并存放成员变量adjMat
    int n = this->vertexes.size();

    int i=0;
    for(; i row;  //创建矩阵的一行对象row
        int j=0;
        for(; jadjMat[rootNo][i];
        if (newDis < v.distance) {
            v.distance = newDis;  //更新顶点i的距离信息

            //TODO: 更新顶点i的路径信息, 提示:调用v对象的一个方法
        }
    }
}

int select() {
//从未曾访问的顶点集合中,选择距离源点最短的顶点(其索引号为minNo)
//返回 minNo
    int minDis = MAX_DIS;
    int minNo = -1;

    int i=0;
    int n = vertexes.size();
    for(; i> slabel;

    int sourceNo;  //源结点索引
    //TODO: 调用一个Graph的成员函数返回标签=slabel的顶点索引号
    //并将编号存入sourceNo

    /
    //2) 初始化源点
    Vertex& source = vertexes[sourceNo];  //获取源点对象source,便于下面代码写作
    //TODO:设置source的isVisited为true
    //TODO:设置source到源点的距离为0
    //TODO: 设置source到源点的路径为[sourceNo]

    //TODO: 以sourceNo为参数调用update成员函数

    //
    //3)Dikstra主算法
    int i=0;
    int n = vertexes.size();
    for(; i<(n-1); ++i) {

        int v;  //当前未访问过的顶点集合中,距离源点的距离最短的顶点索引号为v

        //TODO:调用select方法,并将返回值存入v

        //TODO: v=-1,则退出for循环

        //TODO:将v作为参数,调用update方法
    }

    /
    // 4)打印除源点外的其它顶点信息(按顶点索引号顺序打印)
    string sourceLabel = source.label;
    for(i=0; i

};

int main() {

int t;
cin >> t;

while (t--) {
    Graph g;
    g.main();
}

return 0;

}

输入

第一行输入t,表示有t个测试实例

第二行输入顶点数n和n个顶点信息

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其它结点如果相连则为距离,无连接则为0,数据之间用空格

隔开。第四行输入v0,表示求v0到其他顶点的最短路径距离

以此类推输入下一个示例

输出

对每组测试数据,输出:

每行输出v0到某个顶点的最短距离和最短路径

每行格式:v0编号-其他顶点编号-最短路径值----[最短路径]。没有路径输出:v0编号-其他顶点编号–1。具体请参考示范数据

#include 
#include 
#include 
using namespace std;

//定义无穷大距离
#define MAX_DIS 0x7FFFFF

class Vertex {
public:
    int indexNo;   //顶点索引号:顶点位于顶点数组的下标取值[0,n)
    string label;  //顶点的标签
    int distance;  //顶点到源点的距离
    bool isVisited; //顶点是否已经按Dijkstra算法处理过(不用再处理了)
    vector<int> path; //顶点到源点的路径

    Vertex(int indexNo, const string& label = "", int distance = MAX_DIS) {
        this->label = label;
        this->distance = distance;

        this->indexNo = indexNo;
        this->isVisited = false;
    }
    void updatePath(const vector<int>& prePath) {
        this->path = prePath;   //复制源结点到前一个结点的路径
                                //TODO: 增加本结点到路径数组this->path中
    }

    //打印输出本结点信息
    //输入:顶点数组(供查询用)、源结点索引号(顶点数组下标)
    void displayPath(vector<Vertex>& vertexes, int sourceNo) {

        //0-1-5----[0 1 ]
        cout << vertexes[sourceNo].label; //0
        cout << "-";
        cout << this->label; //1

        cout << "-";
        if (this->distance >= MAX_DIS) {
            //TODO: 如果源结点到本结点距离无穷大,则(按题目要求)输出-1
            return;
        }
        cout << this->distance; //5
        cout << "----";

        cout << "[";
        int i = 0;
        int size = this->path.size();
        for (; i < size; ++i) {
            //TODO: 如果源结点到本结点距离<无穷大,则(按题目要求)输出标签和空格
            cout << path[i] << " ";
        }
        cout << "]";
        cout << endl;
    }
};

//打印顶点信息,供调试用
ostream& operator<<(ostream& out, const Vertex& v) {
    out << v.indexNo << "_" << v.label << ": " << v.distance << " ";
    return out;
}

/
class Graph {
public:
    vector<Vertex> vertexes; //顶点数组:存放顶点信息
    vector<vector<int> > adjMat;  //邻接矩阵:存放每对结点距离,若1对结点i,j之间无边相连,则adjMat[i,j]=0
public:

    void printVertexes() {  //用于调试
        int i = 0;
        int n = vertexes.size();
        for (; i < n; ++i) {
            cout << vertexes[i];
        }
        cout << endl;
    }

    int getNo(string& label) {
        //TODO: 遍历顶点数组vertexes,找到标签属性=label的顶点索引号
        //并返回。
        int i = 0;
        for (; i < vertexes.size(); i++)
        {
            if (label == vertexes[i].label)
                return i;
        }
        return -1;
        //int n = vertexes.size();
    }
    void readVertexes() {
        //读入每个顶点信息
        int n;
        cin >> n;

        int indexNo = 0;
        for (; indexNo < n; ++indexNo) {
            string label;
            //TODO: 读入标签到label变量
            cin >> label;
            Vertex v(indexNo, label);
            //Vertex(int indexNo, const string& label="", int distance=MAX_DIS)
            //TODO: 创建顶点对象v
            this->vertexes.push_back(v);  //把v加入顶点数组
        }

    }
    void readAdjMat() {
        //读取距离矩阵,并存放成员变量adjMat
        int n = this->vertexes.size();
        int i = 0;
        for (; i < n; ++i) {
            vector<int> row;  //创建矩阵的一行对象row
            int j = 0;
            for (; j < n; ++j) {
                int dis;
                cin >> dis;
                row.push_back(dis);
                //TODO: 读取输入的顶点i,j之间的距离,存入变量dis
                //TODO: 将dis插入row
            }
            adjMat.push_back(row);
            //TODO: 将矩阵的一行row附加到邻接矩阵adjMat中
        }
    }

    void update(int rootNo) {
        //将顶点rootNo选入visited集合之后,
        //更新与rootNo关联的所有结点(未访问):到源点的距离、路径信息
        int i = 0;
        int n = vertexes.size();

        Vertex& root = vertexes[rootNo];   //获取rootNo对应顶点对象,便于下面代码写作
        int rootDis = root.distance;

        for (; i < n; ++i) {
            Vertex& v = vertexes[i]; //获取当前顶点对象,便于下面代码写作

            if (v.isVisited)
                //TODO:  如果v已经访问过,则pass

            // TODO: 如果rootNo到i 之间没有边,则pass


            //计算顶点i:到源点的新距离
                int newDis = rootDis + this->adjMat[rootNo][i];
            if (newDis < v.distance) {
                v.distance = newDis;  //更新顶点i的距离信息

                //TODO: 更新顶点i的路径信息, 提示:调用v对象的一个方法
            }
        }
    }

    int select() {
        //从未曾访问的顶点集合中,选择距离源点最短的顶点(其索引号为minNo)
        //返回 minNo
        int minDis = MAX_DIS;
        int minNo = -1;

        int i = 0;
        int n = vertexes.size();
        for (; i < n; ++i) {
            Vertex& v = vertexes[i];

            //TODO:如果顶点i已经访问过,则pass

            if (v.distance < minDis) {
                //TODO:记录顶点i的距离和编号到minDis、minNo中

            }
        }

        //TODO:检查minNo是否为-1,
        //若是,则返回-1

        //获得有效的顶点编号
        vertexes[minNo].isVisited = true;
        return minNo;
    }

    void readSourceNo() {
        //从输入读取源结点标签,执行Dijikstra算法

            /
            //1)读取源点
        string slabel;
        cin >> slabel;

        int sourceNo;  //源结点索引
        //TODO: 调用一个Graph的成员函数返回标签=slabel的顶点索引号
        //并将编号存入sourceNo

        /
        //2) 初始化源点
        Vertex& source = vertexes[sourceNo];  //获取源点对象source,便于下面代码写作
        //TODO:设置source的isVisited为true
        //TODO:设置source到源点的距离为0
        //TODO: 设置source到源点的路径为[sourceNo]

        //TODO: 以sourceNo为参数调用update成员函数

        //
        //3)Dikstra主算法
        int i = 0;
        int n = vertexes.size();
        for (; i < (n - 1); ++i) {

            int v;  //当前未访问过的顶点集合中,距离源点的距离最短的顶点索引号为v

            //TODO:调用select方法,并将返回值存入v

            //TODO: v=-1,则退出for循环

            //TODO:将v作为参数,调用update方法
        }

        /
        // 4)打印除源点外的其它顶点信息(按顶点索引号顺序打印)
        string sourceLabel = source.label;
        for (i = 0; i < n; ++i) {
            //TODO:如果i=sourceNo,则pass

            Vertex& v = vertexes[i];  //获取当前顶点对象v,便于下述代码写作
            //TODO:调用v的一个方法,打印输出源点到顶点v的距离、路径
        }
    }

    void main() {
        readVertexes();  //读取顶点数组
        readAdjMat();    //读取距离矩阵
        readSourceNo();  //读取源点、并执行Dijkstra算法
    }
};


int main() {

    int t;
    cin >> t;

    while (t--) {
        Graph g;
        g.main();
    }

    return 0;
}

【id:102】【20分】F. 道路建设 (Ver. I)

题目描述

有N个村庄,编号从1到N,你应该建造一些道路,使每个村庄都可以相互连接。

两个村A和B是相连的,当且仅当A和B之间有一条道路,或者存在一个村C使得在A和C之间有一条道路,并且C和B相连。

现在一些村庄之间已经有一些道路,你的任务就是修建一些道路,使所有村庄都连通起来,并且所有道路的长度总和是最小的。

输入

测试数据有多组

第一行是整数N(3 <= N <= 100),代表村庄的数量。 然后是N行,其中第i行包含N个整数,这些N个整数中的第j个是村庄i和村庄j之间的距离(距离是[1,1000]内的整数)。

然后是整数Q(0 <= Q <= N *(N + 1)/ 2),接下来是Q行,每行包含两个整数a和b(1 <= a

输出

对于每组测试数据

输出一个整数,表示要构建的道路的长度总和最小值

样例查看模式
正常显示
查看格式
输入样例1 <-复制
3\n
0 990 692\n
990 0 179\n
692 179 0\n
1\n
1 2

#include 
#include 
#include
using namespace std;
//定义无穷大距离
#define MAX_DIS 0x7FFFFF
class Graph {
	int vexNum;
	int** array;
	bool* visit;
	bool isOver();
	int edge = 0;
public:
	Graph();
	void Prim();
	Graph(int N);
};
Graph::Graph(int N) {
	vexNum=N;
	array = new int* [vexNum];
	visit = new bool[vexNum];
	for (int i = 0; i < vexNum; i++)
	{
		visit[i] = false;
		array[i] = new int[vexNum];
		for (int j = 0; j < vexNum; j++)
			array[i][j] = 99999;
	}
	for (int i = 0; i < vexNum; i++)
	{
		for (int j = 0; j < vexNum; j++)
		{
			int weight;
			cin >> weight;
			array[i][j] = weight;
		}
	}
	int Q;
	cin >> Q;
	for (int i = 0; i < Q; i++)
	{
		int a, b;
		cin >> a >> b;
		visit[a-1] = true;
		visit[b-1] = true;
		edge++;
	}
}
void Graph::Prim()
{
	int minWeight = 0;
	while (!isOver())
	{
		int min = 99999, startVex = -1, endVex = -1;
		for (int i = 0; i < vexNum; i++)
		{
			if (visit[i])
			{
				for (int j = 0; j < vexNum; j++)
				{
					if (!visit[j] && array[i][j] < min) {
						min = array[i][j];
						startVex = i;
						endVex = j;
					}
				}
			}
		}
		visit[endVex] = true;
		this->edge++;
		minWeight += min;	
	}
	if (edge < (vexNum - 1))
	{
		int minP = MAX_DIS;
		for (int i = 0; i < vexNum; i++)
		{
			for (int j = 0; j < vexNum; j++)
			{
				if (array[i][j] && array[i][j] < minP)
				{
					minP = array[i][j];
				}
			}
		}
		cout << minP << endl;
	}
	else
		cout << minWeight << endl;
	
}
bool Graph::isOver() {
	for (int i = 0; i < vexNum; i++)
		if (!visit[i])
			return false;
	return true;
}
int main()
{
	int N;
	while (cin >> N)
	{
		Graph graph(N);
		graph.Prim();
	}
}

DS二叉排序树之创建和插入

题目描述

给出一个数据序列,建立二叉排序树,并实现插入功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

输入

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要插入m个数据

从第五行起,输入m行,每行一个要插入的数据,都是自然数且和前面的数据不等

以此类推输入下一个示例

输出

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出插入第m个数据后的有序序列,输出m行

以此类推输出下一个示例的结果

#include
#include
#include
#include
using namespace std;
class Node
{
public:
    int value;
    Node* lchild, * rchild;
};
class Tree
{
public:
   Node* root;
   int n;
   vectorv;
   int index = 0;
   Tree(vectorv)
   {
       this->n = v.size();
       this->v = v;
       root = new Node();
       root->value = v[index++];
       for (; index < n; index++) {
           Create(root, v[index]);
       }
   }
   void Create(Node*root,int value)
   {
       if (value < root->value)
       {
           if (root->lchild == nullptr)
           {
               root->lchild = new Node();
               root->lchild->value = value;
               return;
           }
           else
           {
               Create(root->lchild, value);
           }
       }
       else
       {
           if (root->rchild == nullptr) {
               root->rchild = new Node();
               root->rchild->value = value;
           }
           else
           {
               Create(root->rchild, value);
           }
       }
   }
   void inorder(Node* root)
   {
       if (root == nullptr)
           return;
       inorder(root->lchild);
       cout << root->value << " ";
       inorder(root->rchild);
   }
};
int main()
{
    int  t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        vectorv;
        for (int i = 0; i < n; i++)
        {
            int digit;
            cin >> digit;
            v.push_back(digit);
        }
        Tree tree = Tree(v);
        tree.inorder(tree.root);
        cout << endl;
        int m;
        cin >> m;
        while (m--)
        {
            int digit;
            cin >> digit;
            tree.Create(tree.root, digit);
            tree.inorder(tree.root);
            cout << endl;
        }
    }
}

二叉平衡树练习

【id:158】【10分】F. 二叉平衡树练习
时间限制
1s
内存限制
128MB
题目描述

对二叉平衡树进行四种操作:

1 D K 表示插入一个新数据,数据为D用于输出,关键值为K用于排序;
2 输出当前树中最大关键值所带的数据,并删除该数据,如果没有这个关键值,则输出0;
3 输出当前树中最小关键值所带的数据,并删除该数据,如果没有这个关键值,则输出0;
4 K 输出关键值为 K 的数据,并删除该数据,如果没有这个关键值,则输出0。
要求必须实现平衡树,不可以使用各类库函数

AVL代码模板参考:

#include
const int maxn = 1e5 + 10;
struct Node
{
int key; // 关键值
int data; // 携带的数据
int left; // 左子树地址(数组下标)
int right; // 右子树地址(数组下标)
int height; // 当前结点为根的子树高度
void Init(){data = key = left = right = height = -1;}
void Init(int k_, int d_=0){Init(); key = k_; data = d_;}
Node(){Init();}
Node(int k_, int d_=0){Init(k_, d_);}
};

Node tr[maxn];
int root, tp; // root标记根节点位置,tp全局结点分配下标

inline int UpdateHeight(int now)
{
// 更新 tr[now] 结点的子树高度,即tr[now].height的值
}
inline int HeightDiff(int now)
{
// 计算 tr[now] 结点的平衡因子
}
int LL(int an)
{
}
int RR(int an)
{
}
int LR(int an)
{
}
int RL(int an)
{
}
void Insert(int &now, int key, int data=0)
{
if(now == -1)
{
// 传入指针为空,新建结点保存数据
now = ++ tp;
tr[now].Init(key, data);
}
// 判断插入哪个子树,插入数据,判断平衡因子,做正确旋转,更新高度
}
void Delete(int &now, int key)
{
if(now == -1) return;
else if(key < tr[now].key) Delete(tr[now].left, key);
else if(key > tr[now].key) Delete(tr[now].right, key);
else
{
// 删除当前结点
}
// 处理树平衡
}

int main()
{
int n, op, key, data;
while(scanf(“%d”, &n) != EOF)
{
for(root = tp = -1; n --; ) // 初始化根结点和“内存指针”
{
scanf(“%d”, &op);
if(op == 1)
{
}
else if(op == 2)
{
}
else if(op == 3)
{
}
else
{
}
}
return 0;
}

输入

每组数据第一行n表示有n个操作

接下来n行操作内容

输出

按操作规则输出对应内容

样例查看模式
正常显示
查看格式
输入样例1 <-复制
8\n
2\n
1 20 14\n
1 30 3\n
2\n
1 10 99\n
3\n
2\n
2

#include
using namespace std;
const int maxn = 1e5 + 10;
struct Node
{
    int key;        // 关键值
    int data;       // 携带的数据
    int left;       // 左子树地址(数组下标)
    int right;      // 右子树地址(数组下标)
    int height;     // 当前结点为根的子树高度
    void Init() { data = key = left = right = height = -1; }
    void Init(int k_, int d_ = 0) { Init(); key = k_; data = d_; }
    Node() { Init(); }
    Node(int k_, int d_ = 0) { Init(k_, d_); }
};

Node tr[maxn];
int root, tp;  // root标记根节点位置,tp全局结点分配下标

void preOrder(int now, int depth, int& maxDepth)
{
    if (tr[now].key != -1)
    {
        depth++;
        if (depth > maxDepth)
            maxDepth = depth;
        preOrder(tr[now].left, depth, maxDepth);
        preOrder(tr[now].right, depth, maxDepth);
    }
}
inline int UpdateHeight(int& now)
{
    // 更新 tr[now] 结点的子树高度,即tr[now].height的值
    int depth = 0;
    int maxDepth = 0;
    preOrder(now, depth, maxDepth);
    tr[now].height = maxDepth;
    return maxDepth;
}
inline int HeightDiff(int now)
{
    // 计算 tr[now] 结点的平衡因子
    return tr[tr[now].left].height - tr[tr[now].right].height;
}
int LL(int &an)
{
    int rc = tr[an].right;
    tr[an].right = tr[rc].left;
   tr[ rc].left = an;
   an = rc;
}
int RR(int &an)
{
    int lc = tr[an].left;
    tr[an].left = tr[lc].right;
    tr[lc].right = an;
    an = lc;
}
int LR(int an)
{
}
int RL(int an)
{
}
void LeftBalance(int &now)
{
    Node lc = tr[tr[now].left];
    int balance = HeightDiff(lc.left) - HeightDiff(lc.right);
    switch (balance)
    {
    case 1:
        RR(now);
        UpdateHeight(now);///旋转之后更新高度
        break;
    case -1:
        LL(tr[now].left);
        RR(now);
        UpdateHeight(tr[now].left);
        UpdateHeight(now);
    }

}
void RightBalance(int &now)
{
    Node rc = tr[tr[now].right];
    int balance = HeightDiff(rc.left) - HeightDiff(rc.right);
    switch (balance)
    {
    case 1:
        LL(now);
        UpdateHeight(now);///旋转之后更新高度
        break;
    case -1:
        RR(tr[now].left);
        LL(now);
        UpdateHeight(tr[now].right);
        UpdateHeight(now);
    }

}
void Insert(int& now, int key, int data = 0)
{
    if (now == -1)
    {
        // 传入指针为空,新建结点保存数据
        now = ++tp;
        tr[now].Init(key, data);
    }
    if (tr[now].key == key) return;
    if (tr[now].key > key  )此节点小于根节点的值
    {
        Insert(tr[now].left, key, data);在左子树中插入
        UpdateHeight(now);插入之后回溯,要更新当然节点树的高度
        int balance = HeightDiff(now);计算得到平衡因子
        if (balance >= 2)
        {
            LeftBalance(now);左子树长高只有可能需要左平衡
        }
    }
    else
    {
        Insert(tr[now].right, key, data);///在右子树中插入
        UpdateHeight(now);插入之后回溯,要更新当然节点树的高度
        int balance = HeightDiff(now);计算得到平衡因子
        if (balance <= -2)
        {
            RightBalance(now);左子树长高只有可能需要右平衡
        }
    }
    // 判断插入哪个子树,插入数据,判断平衡因子,做正确旋转,更新高度
}
void Delete(int& now, int key,int father)
{
    if (now == -1) return;
    else if (key < tr[now].key) Delete(tr[now].left, key,now);
    else if (key > tr[now].key) Delete(tr[now].right, key,now);
    else
    {
        if (tr[now].left != -1 && tr[now].right != -1)有左右孩子
        {
            int q = now;
            int s = tr[now].left;
            while (tr[s].right != -1)
            {
                q = s;
                s = tr[s].right;
            }
            tr[now] = tr[s];
            if (q != now)
            {
                tr[q].right = tr[s].left;
            }
            else
            {
                tr[q].left = tr[s].left;
            }
        }
        else if (tr[now].left != -1)
        {
            if (father == -1)father = tr[now].left;
            else if (now == tr[father].right)
                tr[father].right = tr[now].left;
            else tr[father].left = tr[now].left;


        }
        else if (tr[now].right != -1)   只有右孩子
        {
            if (father == -1)father = tr[now].right;
            else if (now == tr[father].right)
                tr[father].right = tr[now].right;
            else
                tr[father].left = tr[now].right;

        }
        else   没有孩子
        {
            if (father == -1) now = -1;
            else if (now == tr[father].left)
                tr[father].left = -1;
            else tr[father].right = -1;

        }
        // 删除当前结点
    }
    LeftBalance(now);
    RightBalance(now);
    // 处理树平衡
}
void findMinKey(int now, int& maxn,int &index)
{
    if (now != -1)
    {
        if (tr[now].key > maxn)
        {
            maxn = tr[now].key;
            index = now;
        }
        findMinKey(tr[now].left, maxn, index);
        findMinKey(tr[now].right, maxn, index);
    }
}
int findMin(int root)
{

    int minKey = maxn;
    int index = -1;
    findMinKey(root, minKey,index);
    return index;

}
int main()
{
    int n, op, key, data;
    while (scanf("%d", &n) != EOF)
    {
        for (root = tp = -1; n--; )  // 初始化根结点和“内存指针”
        {
            scanf("%d", &op);
            if (op == 1)
            {
                cin >> data >> key;
                Insert(tp, key, data);
            }
            else if (op == 2)
            {
                int index = findMin(tp);
                if (index == -1)
                    cout << 0;
                else
                {
                    cout << tr[index].data;
                    Delete(tp, tr[index].key, -1);
                }
            }
            else if (op == 3)
            {


            }
            else
            {


            }
        }
        return 0;
    }

你可能感兴趣的:(数据结构,数据结构,算法)