做完(看完)发现,这套题都是组合数学的多,可是几乎都没学过啊! 所以只做出了三题,接下来的题目,先学算法,再补上吧。
晚上的CF,到底能不能脱离灰名呢, 呃, 还得看晚上报不报名, 报了, 还得看 会不会做、、、、 - -#
A - 过山车
Problem Description
RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗?
Input
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。
Output
对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。
Sample Input
6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0
Sample Output
3
简单的 二分图最大匹配,没想那么多,取值的时候,我是直接去n m 里面大的那个数,AC了, 也就没管了、、
#include <stdio.h> #include <string.h> #include <vector> using namespace std; #define N 520 vector<int> mpt[N]; int linker[N]; bool vis[N]; void init(int n) { for(int i = 1; i <= n; i ++) { mpt[i].clear(); } } bool dfs(int n) { for(int i = 0; i < mpt[n].size(); i ++) { if(!vis[ mpt[n][i] ]) { vis[ mpt[n][i] ] = true; if(!linker[ mpt[n][i] ] || dfs( linker[ mpt[n][i] ])) { linker[ mpt[n][i] ] = n; return true; } } } return false; } int getsum(int n) { int cnt = 0; memset(linker, 0, sizeof(linker)); for(int i = 1; i <= n; i ++) { memset(vis, false, sizeof(vis)); if(dfs(i)) cnt ++; } return cnt; } int main() { int t, m, n, tt; int a, b; while(~scanf("%d",&t)) { if(t == 0) break; scanf("%d%d",&n, &m); tt = max(n, m); init(tt); for(int i = 0; i < t; i ++) { scanf("%d%d",&a, &b); mpt[a].push_back(b); } printf("%d\n",getsum(tt)); } return 0; }
B - 汉诺塔III
Problem Description
约19世纪末,在欧州的商店中出售一种智力玩具,在一块铜板上有三根杆,最左边的杆上自上而下、由小到大顺序串着由64个圆盘构成的塔。目的是将最左边杆上的盘全部移到右边的杆上,条件是一次只能移动一个盘,且不允许大盘放在小盘的上面。
现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。
Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?
现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。
Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?
Input
包含多组数据,每次输入一个N值(1<=N=35)。
Output
对于每组数据,输出移动最小的次数。
Sample Input
1 3 12
Sample Output
2 26 531440
画了满满两面的 试卷大的草稿纸, 结果公式还搞错了, 差一点! 我想知道,稍微数据大一点的,或者复杂的递推题要怎么搞- -||
#include <stdio.h> #include <string.h> #include <iostream> #include <string> #include <algorithm> #include <map> using namespace std; __int64 f[40]; int main() { int n; f[1] = 2; f[2] = 8; for(int i = 3; i <= 36; i ++) { f[i] = f[i - 1] * 3 + 2; } while(~scanf("%d", &n)) { printf("%I64d\n", f[n]); } }
E - 小兔的棋盘
Problem Description
小兔的叔叔从外面旅游回来给她带来了一个礼物,小兔高兴地跑回自己的房间,拆开一看是一个棋盘,小兔有所失望。不过没过几天发现了棋盘的好玩之处。从起点(0,0)走到终点(n,n)的最短路径数是C(2n,n),现在小兔又想如果不穿越对角线(但可接触对角线上的格点),这样的路径数有多少?小兔想了很长时间都没想出来,现在想请你帮助小兔解决这个问题,对于你来说应该不难吧!
Input
每次输入一个数n(1<=n<=35),当n等于-1时结束输入。
Output
对于每个输入数据输出路径数,具体格式看Sample。
Sample Input
1 3 12 -1
Sample Output
1 1 2 2 3 10 3 12 416024
简单的DP, 突然感觉,自己又水了一场比赛, 看来、、、、、好吧、、。 这场比赛就这样吧、、、
#include<stdio.h> #include<math.h> #include<string.h> typedef long long ll; ll dp[40][40]; void init() { for(int i = 1; i < 40 ; i ++) dp[1][i] = 1; for(int i = 2; i <40; i ++) { dp[i][i] = dp[i-1][i]; for(int j = i + 1; j < 40; j ++) dp[i][j] = dp[i-1][j] + dp[i][j-1]; } } int main() { int n,t = 1; init(); while(~scanf("%d",&n)) { if(n == -1) break; printf("%d %d %I64d\n",t++,n,2*dp[n+1][n+1]); } return 0; }
F - RPG的错排
Problem Description
今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但做为集训队成员之一的野骆驼竟然不知道RPG三个人具体是谁谁。RPG给他机会让他猜猜,第一次猜:R是公主,P是草儿,G是月野兔;第二次猜:R是草儿,P是月野兔,G是公主;第三次猜:R是草儿,P是公主,G是月野兔;......可怜的野骆驼第六次终于把RPG分清楚了。由于RPG的带动,做ACM的女生越来越多,我们的野骆驼想都知道她们,可现在有N多人,他要猜的次数可就多了,为了不为难野骆驼,女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。
Input
输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。
Sample Input
1 2 0
Sample Output
1 1
很容易找出公式,当然, 你还要知道一个错排(一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排)公式,就更简单了。 错排公式: D(n) = (n - 1) * ( D (n - 2) + D (n - 1) )
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; __int64 c(int n,int m) { __int64 a = 1; if(m == 0) return 1; for(int i = 1; i <= m; i ++) { a = a* (n - i + 1); a = a / i; } return a; } int main() { int n; __int64 tt[30]; tt[1] = 0; tt[2] = 1; for(int i = 3; i <= 13; i ++) { tt[i] = (i - 1) * (tt[i - 1] + tt[i - 2]); } while(~scanf("%d",&n), n) { __int64 sum = 1; for(int i = 1; i <= n/2 ; i ++) { sum += c(n, i)* tt[i]; } printf("%I64d\n", sum); } }