理论部分:
1.卡特兰数的应用
出栈次序
一个栈(无穷大)的进栈序列为1,2,3,…,n,有多少个不同的出栈序列?
f(n)=h(n)= C(2n,n)/(n+1)= c(2n,n)-c(2n,n-1)
例如:
编号为1,2,3,4的四辆列车,顺序开进一个栈式结构的站台;则开出车站的顺序有__种可能。
枚举思路:
先进站的车可以先开,也可以后开。只有一种情况不可能:编号大的车开出后,比其编号小的车反序开出。也即编号大的车开出后,编号比其小的车只能由大到小依次开出(中间可以插入编号更大的车,但此车后面的编号小的车也要遵守此规则)。例如312的开出顺序是不可能的。对所有车进行全排列共有24种出法。但4开头的只能有一种:4321。所以少了3的全排列-1=5种。三开头的时候,必须先2后1开出,先1后2时4的位置有三种:3124、3142、3412,所以少了三种。1或2开头的时候,后面的车如果是4,则最后两辆必须是3、2或3、1。所以又少了1423、2413两种。总共少了5+3+2=10种,有24-10=14种开出法。
1 约瑟夫问题(Monkey king election)
描述
有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入输入包含两个整数,第一个是n,第二个是m 1 < m,n<=300
输出输出包含一行,即最后猴王的编号。
样例输入12 4
样例输出1
//单循环链表解答
#include <iostream>
using namespace std;
struct monkey {
int num;//号码
monkey *next;//链表节点
};
int joseph(int sum,int cycle) {
int i;
monkey *cur, *nex, *head = NULL;
head = new monkey;
//此处创建一个循环链表
head->num = 1;
cur = head;
for (i = 2; i <= sum; i++) {
nex = new monkey;
nex->num = i;
cur->next = nex;
cur = nex;
}
cur->next=head;
cur = head;
i = 1;
//循环删除元素直到只剩下最后一个元素
while (1) {
nex = cur->next;
i++;
if (nex == cur)
break;
if ((i%cycle) == 0) {
cur->next = nex->next;
cur = cur->next;
delete nex;
i = 1;
}
else {
cur = nex;
}
}
return nex->num;
}
int main(void) {
int n, m;
cin >> n >> m;
cout << joseph(n, m) << endl;
return 0;
}
2 多项式加法
描述
我们经常遇到两多项式相加的情况,在这里,我们就需要用程序来模拟实现把 两个多项式相加到一起。首先,我们会有两个多项式,每个多项式是独立的一行,每个多项式由系数、幂数这样的多个整数对来表示。 如多项式2x20- x17+ 5x9- 7x7+ 16x5+ 10x4 + 22x2- 15 对应的表达式为:2 20 -1 17 5 9 - 7 7 16 5 10 4 22 2 -15 0。
为了标记每行多项式的结束,在表达式后面加上了一个幂数为负数的整数对。 同时输入表达式的幂数大小顺序是随机的。 我们需要做的就是把所给的两个多项式加起来。
输入输入包括多行。
第一行整数n,表示有多少组的多项式需要求和。(1< n < 100)
下面为2n行整数,每一行都是一个多项式的表达式。表示n组需要相加的多项式。
每行长度小于300。
输出输出包括n行,每行为1组多项式相加的结果。
在每一行的输出结果中,多项式的每一项用“[x y]” 形式的字符串表示,x是该项的系数、y是该项的幂数。要求按照每一项的幂从高到低排列,即先输出幂数高的项、再输出幂数低的项。
系数为零的项不要输出。
样例输入2
-1 17 2 20 5 9 -7 7 10 4 22 2 -15 0 16 5 0 -1
2 19 7 7 3 17 4 4 15 10 -10 5 13 2 -7 0 8 -8
-1 17 2 23 22 2 6 8 -4 7 -18 0 1 5 21 4 0 -1
12 7 -7 5 3 17 23 4 15 10 -10 5 13 5 2 19 9 -7
样例输出[ 2 20 ] [ 2 19 ] [ 2 17 ] [ 15 10 ] [ 5 9 ] [ 6 5 ] [ 14 4 ] [ 35 2 ] [ -22 0 ]
[ 2 23 ] [ 2 19 ] [ 2 17 ] [ 15 10 ] [ 6 8 ] [ 8 7 ] [ -3 5 ] [ 44 4 ] [ 22 2 ] [ -18 0 ]
#include <iostream>
using namespace std;
struct item {
int k, ex;//系数,次数
item *next;
};//单链表节点
item equalmark;
//用来在链表中查找ex与当前值相等的链表元素
item *search(item *current, item *head) {
while (head->next != NULL) {
if (current->ex == head->next->ex) {
head->next->k += current->k;
delete current;
return &equalmark;
}
if (current->ex > head->next->ex)
break;//current次数高于head下一项,把current插进head位
head = head->next;
}
return head;
}
int main() {
int inputnum;
cin >> inputnum;
while (inputnum--) {
item *head = NULL, *current = NULL;
int k, ex;
for (int i = 0; i <= 1; i++) {//两行多项式
while (cin >> k >> ex, ex >= 0) {
current = new item;
current->k=k, current->ex = ex, current->next = NULL;
if (head == NULL)
head = current;
else if (current->ex > head->ex) {//这其实是边输入边计算并按次数大到小排
current->next = head;
head = current;
}//出现新的最高次项
else if (current->ex == head->ex) {
(head->k)+=(current->k);
delete current;
}//和head同次
else {
item *temp = search(current, head);
if (temp != &equalmark) {
current->next = temp->next;//之前在这里犯了点小错..注意不是head而是temp,head传进函数但外面没变
temp->next = current;
}
}
}
}
current = head;
//遍历加法之后得到的链表,输出结果
while (current->next != NULL) {
if (current->k != 0)
cout << "[ " << current->k << ' ' << current->ex << " ] ";
current = current->next;
}
if (current->k != 0)
cout << "[ " << current->k <<' ' << current->ex << " ] ";
if (inputnum > 0)
cout << endl;
while (head != NULL) {
item *temp = head->next;
delete head;
head = temp;
}
}
return 0;
}