您的位置:首页 > 其它

HDU 1133(卡特兰数;动态规划)

2014-01-14 16:59 405 查看
题意:M+N个人排队买票,票的单价是50¥,每个人只能买一张。 M个人拿50的去买,N个人拿100的去买,然后悲剧的是售票处开始的时候没有钱,所以如果拿100块买票人前面的拿50块买票的人小于或者等于用100块买票的人,这种排队方式就不合法,也就是不能顺利全部都买到票(因为没零钱找了)!

题目分析:

这是一个Catalan数的非常经典的应用,买票问题,首先我们用"0"表示用50块买票的人,用“1”表示用100块买票的人,然而假设m=4,n=3,的一个序列是:0110100显然,它不合法,然后我们把他稍微变化一下:把第一个不合法的“1”后面的所有数0位为1, 1位为0;这样我们得到了另一个序列:0111011,显然他也不是合法的,但是在这里我们关注的不是他合不合法!只是说明每个不合法的都有一个这样的序列跟他一一对应!

所以我们计算公式就是:合法的排列方式=所有排列方式-非法排列方式

我们这里非法排列方式的计算 就是:(

 - 


)*M!*N!,然而在这题,因为每个人都是不同的,所以还要乘以 M!*N!

所以得出最终方程:

F(N)= (

 - 


)*M!*N!,

然后再化简一下;

F(N)=(M+N)! * (M-N+1)/(M+1)

 

卡特兰数方法:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cstdlib>
using namespace std;

#define MAXN 300

class Number
{
private:
static int _t[MAXN];
int* num;
int len;
Number(int l, int* t)
{
len = l;
num = new int[len];
memcpy(num, t, sizeof(int) * len);
}
public:
Number(unsigned int n)
{
if (n == 0)
{
num = new int[2];
len = 2;
num[1] = 0;
num[0] = -1;
return;
}
int t = MAXN;
while (n > 0)
{
_t[--t] = n%10000;
n /= 10000;
}
len = MAXN - t;
num = new int[len];
memcpy(num, _t+t, sizeof(int) * len);
}
Number()
{
num = new int[1];
len = 1;
num[0] = 0;
}
Number operator=(const Number& rhs)
{
delete[] num;
len = rhs.len;
num = new int[len];
memcpy(num, rhs.num, sizeof(int) * len);
return *this;
}
Number(const Number& rhs)
{
len = rhs.len;
num = new int[len];
memcpy(num, rhs.num, sizeof(int) * len);
}
~Number()
{
delete[] num;
}
friend ostream& operator<< (ostream& os, const Number& rhs)
{
printf("%d", rhs.num[0]);
for (int i = 1; i < rhs.len; ++i)
{
printf("%04d", rhs.num[i]);
}
return os;
}
Number operator/ (const unsigned int n) const
{
int i, l = len, carry = 0;
for (i = 0; i < l; ++i)
{
carry = carry*10000+num[i];
_t[i] = carry/n;
carry %= n;
}
for (i = 0; i < l; ++i)
if (_t[i]) break;
if (i == l) i = l-1;
return Number(l-i, _t+i);
}
Number operator* (const unsigned int n) const
{
if (n > INT_MAX/10000)
{
cout << "失败:" << n << endl;
exit(EXIT_FAILURE);
}
int t = MAXN, l = len, carry = 0;
while (l > 0)
{
carry += num[--l] * n;
_t[--t] = carry % 10000;
carry /= 10000;
}
while (carry)
{
_t[--t] = carry % 10000;
carry /= 10000;
}
return Number(MAXN-t, _t+t);
}
Number operator+ (const Number& rhs)
{
int t = MAXN, l1 = len, l2 = rhs.len, carry = 0;
while (l1 > 0 && l2 > 0)
{
carry += rhs.num[--l2] + num[--l1];
_t[--t] = carry % 10000;
carry /= 10000;
}
while (l2 > 0)
{
carry += rhs.num[--l2];
_t[--t] = carry % 10000;
carry /= 10000;
}
while (l1 > 0)
{
carry += num[--l1];
_t[--t] = carry % 10000;
carry /= 10000;
}
if (carry) _t[--t] = carry;
return Number(MAXN-t, _t+t);
}
friend Number operator+ (const unsigned int n, const Number& rhs)
{
return Number(n) + rhs;
}
friend Number operator* (const unsigned int n, const Number& rhs)
{
return rhs.operator* (n);
}
};
int Number::_t[MAXN];
Number fact[201];
int main()
{
int n, m, i, count = 1;
fact[0] = fact[1] = 1;
for (i = 2; i <= 200; ++i)
fact[i] = fact[i-1]*i;
while (cin >> m >> n)
{
if (m == 0 && n == 0) break;
cout << "Test #" << count++ << ":" << endl;
if (n > m) cout << 0 << endl;
else
{
cout << fact[n+m]*(m-n+1)/(m+1) << endl;
}
}
return 0;
}


动态规划代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cstdlib>
using namespace std;

#define MAXN 300

class Number
{
private:
static int _t[MAXN];
int* num;
int len;
Number(int l, int* t)
{
len = l;
num = new int[len];
memcpy(num, t, sizeof(int) * len);
}
public:
Number(unsigned int n)
{
if (n == 0)
{
num = new int[2];
len = 2;
num[1] = 0;
num[0] = -1;
return;
}
int t = MAXN;
while (n > 0)
{
_t[--t] = n%10000;
n /= 10000;
}
len = MAXN - t;
num = new int[len];
memcpy(num, _t+t, sizeof(int) * len);
}
Number()
{
num = new int[1];
len = 1;
num[0] = 0;
}
Number operator=(const Number& rhs)
{
delete[] num;
len = rhs.len;
num = new int[len];
memcpy(num, rhs.num, sizeof(int) * len);
return *this;
}
Number(const Number& rhs)
{
len = rhs.len;
num = new int[len];
memcpy(num, rhs.num, sizeof(int) * len);
}
~Number()
{
delete[] num;
}
friend ostream& operator<< (ostream& os, const Number& rhs)
{
printf("%d", rhs.num[0]);
for (int i = 1; i < rhs.len; ++i)
{
printf("%04d", rhs.num[i]);
}
return os;
}
Number operator* (const unsigned int n) const
{
if (n > INT_MAX/10000)
{
cout << "失败:" << n << endl;
exit(EXIT_FAILURE);
}
int t = MAXN, l = len, carry = 0;
while (l > 0)
{
carry += num[--l] * n;
_t[--t] = carry % 10000;
carry /= 10000;
}
while (carry)
{
_t[--t] = carry % 10000;
carry /= 10000;
}
return Number(MAXN-t, _t+t);
}
Number operator+ (const Number& rhs)
{
int t = MAXN, l1 = len, l2 = rhs.len, carry = 0;
while (l1 > 0 && l2 > 0)
{
carry += rhs.num[--l2] + num[--l1];
_t[--t] = carry % 10000;
carry /= 10000;
}
while (l2 > 0)
{
carry += rhs.num[--l2];
_t[--t] = carry % 10000;
carry /= 10000;
}
while (l1 > 0)
{
carry += num[--l1];
_t[--t] = carry % 10000;
carry /= 10000;
}
if (carry) _t[--t] = carry;
return Number(MAXN-t, _t+t);
}
friend Number operator+ (const unsigned int n, const Number& rhs)
{
return Number(n) + rhs;
}
friend Number operator* (const unsigned int n, const Number& rhs)
{
return rhs.operator* (n);
}
};
int Number::_t[MAXN];

Number res[109][109];

int main()
{
int n, m, i, j, count = 1;
res[0][0] = 1;
while (cin >> m >> n)
{
if (m == 0 && n == 0) break;
for (i = 1; i <= m; ++i)
res[i][0] = res[i-1][0]*(m-i+1);
for (i = 1; i <= m; ++i)
for (j = 1; j <= i && j <= n; ++j)
res[i][j] = res[i-1][j]*(m-i+1) + res[i][j-1]*(n-j+1);
cout << "Test #" << count++ << ":" << endl << res[m]
<< endl;
}
return 0;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息