BZOJ1002輪狀病毒 暴搜 + 找規律 + 高精度

@[暴搜, 找規律, 高精度]

Description

轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个\(n\)轮状基由圆环上\(n\)个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示
enter image description here
\(n\)轮状病毒的产生规律是在一个\(n\)轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有\(16\)个不
同的3轮状病毒,如下图所示
enter image description here
现给定\(n\)(\(n <= 100\)),编程计算有多少个不同的n轮状病毒

Input

1个正整数n

Output

计算出的不同的n轮状病毒数输出

Sample Input

3

Sample Output

16

Solution

先暴搜找規律(結果爆搜就打了好久\(QAQ\))

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
inline int read()
{
    int x = 0, flag = 1;;
    char c;
    while(! isdigit(c = getchar()))
        if(c == '-')
            flag *= - 1;
    while(isdigit(c))
        x = x * 10 + c - '0', c = getchar();
    return x * flag;
}
void println(int x)
{
    if(x < 0)
        putchar('-'), x *= - 1;
    if(x == 0)
        putchar('0');
    int ans[10], top = 0;
    while(x)
        ans[top ++] = x % 10, x /= 10;
    for(; top; top --)
        putchar(ans[top - 1] + '0');
    putchar('\n');
}
int n;
struct Edge
{
	int u, v;
}G[100];
int ans;
int fa[16];
int find(int x)
{
	if(fa[x] == x)
		return x;
	return fa[x] = find(fa[x]);
}
void search(int x, int top, int cnt)
{
	if(cnt == n)
	{
		ans ++;
		return;
	}
	if(x == top)
		return;
 	search(x + 1, top, cnt);
	int _fa[16]; //并查集很執行難撤回操作, 因此只能用這種比較笨的辦法來搞
	for(int i = 0; i <= n; i ++)
		_fa[i] = fa[i];
	int fu = find(G[x].u), fv = find(G[x].v);
	if(fu == fv)
		return;
	fa[fu] = fv;
	search(x + 1, top, cnt + 1);
	for(int i = 0; i <= n; i ++)
		fa[i] = _fa[i];
}
int main()
{
	for(int i = 2; i < 16; i ++)
	{
		n = i;
		for(int j = 0; j < n; j ++)
			G[j].u = 0, G[j].v = j + 1;
		for(int j = n; j < (n << 1); j ++)
			G[j].u = j - n + 1, G[j].v = j - n + 2;
		G[(n << 1) - 1].v = 1;
		for(int i = 0; i <= n; i ++)
			fa[i] = i;
		ans = 0;
		search(0, n << 1, 0);
		println(ans);
	}
}

得到輸出數據

5
16
45
121
320
841
2205
5776
15125
39601
103680
271441
710645
1860496

--------------------------------
Process exited after 70.46 seconds with return value 0
请按任意键继续. . .

通過待定係數法可得, 對於\(n\)輪狀病毒有種類數
\(f(n) = f(n - 1) * 3 - f(n - 2) + 2\)
注意到當 \(n = 100\)\(f(n)\) 會變得很大, 所以要寫高精度...

#include<cstdio>
#include<cctype>
#include<cstring>
using namespace std;
inline int read()
{
    int x = 0, flag = 1;;
    char c;
    while(! isgraph(c = getchar()))
        if(c == '-')
            flag *= - 1;
    while(isgraph(c))
        x = x * 10 + c - '0', c = getchar();
    return x * flag;
}
void println(int x)
{
    if(x < 0)
        putchar('-'), x *= - 1;
    if(x == 0)
        putchar('0');
    int ans[10], top = 0;
    while(x)
        ans[top ++] = x % 10, x /= 10;
    for(; top; top --)
        putchar(ans[top - 1] + '0');
    putchar('\n');
}
const int N = 1 << 7;
struct Giant
{
	int dig[1 << 10];
	int top;
}f[N];
Giant operator *(Giant x, int y)
{
	for(int i = 0; i < x.top; i ++)
		x.dig[i] *= y;
	for(int i = 0; i < x.top; i ++)
		x.dig[i + 1] += x.dig[i] / 10, x.dig[i] %= 10;
	if(x.dig[x.top])
		x.top ++;
	return x;
}
Giant operator -(Giant x, Giant y)
{
	for(int i = 0; i < x.top; i ++)
	{
		x.dig[i] -= y.dig[i];
		if(x.dig[i] < 0)
			x.dig[i] += 10, x.dig[i + 1] --;
	}
	if(! x.dig[x.top - 1])
		x.top --;
	return x;
}
Giant operator +(Giant x, int y)
{
	x.dig[0] += y;
	for(int i = 0; i < x.top; i ++)
		x.dig[i + 1] += x.dig[i] / 10, x.dig[i] = x.dig[i] % 10;
	if(x.dig[x.top])
		x.top ++;
	return x;
}
void println(Giant &x)
{
	for(int i = x.top; i; i --)
		putchar(x.dig[i - 1] + '0');
	putchar('\n');
}
int main()
{
	int n = read();
	memset(f, 0, sizeof(f));
	f[2].dig[0] = 5, f[2].top = 1;
	f[3].dig[0] = 6, f[3].dig[1] = 1, f[3].top = 2;
	for(int i = 4; i <= n; i ++)
		f[i] = f[i - 1] * 3 - f[i - 2] + 2;
	println(f[n]);
}
posted @ 2017-03-01 10:22  Zeonfai  阅读(199)  评论(0编辑  收藏  举报