• nyoj--127--星际之门(一)(生成树的数量)


    星际之门(一)

    时间限制:3000 ms  |  内存限制:65535 KB
    难度:3
    描述

    公元3000年,子虚帝国统领着N个星系,原先它们是靠近光束飞船来进行旅行的,近来,X博士发明了星际之门,它利用虫洞技术,一条虫洞可以连通任意的两个星系,使人们不必再待待便可立刻到达目的地。

    帝国皇帝认为这种发明很给力,决定用星际之门把自己统治的各个星系连结在一起。

    可以证明,修建N-1条虫洞就可以把这N个星系连结起来。

    现在,问题来了,皇帝想知道有多少种修建方案可以把这N个星系用N-1条虫洞连结起来?

     

    输入
    第一行输入一个整数T,表示测试数据的组数(T<=100)
    每组测试数据只有一行,该行只有一个整数N,表示有N个星系。(2<=N<=1000000)
    输出
    对于每组测试数据输出一个整数,表示满足题意的修建的方案的个数。输出结果可能很大,请输出修建方案数对10003取余之后的结果。
    样例输入
    2
    3
    4
    样例输出
    3
    16
    来源
    [张云聪]原创
    上传者

    张云聪

    我也不清楚为毛线这一道题为什麽会出现在图论中,大概是证明过程,参考大神的证明:

    简单点说就是:
    一一对应法:
    假定T是其中一棵树,树叶中有标号最小者,设为a1,a1的邻接点为b1,从图中消去a1点
    和边(a1, b1).b1点便成为消去后余下的树T1的顶点.在余下的树T1中寻找标号最小的树叶,设
    为a2,a2的邻接点为b2,从T1中消去a2及边(a2, b2).如此步骤继续n-2次,直到最后剩下一条
    边为止.于是一棵树T对应一序列
    b1,b2,…,b[n-2]
    恢复树T:
    序列I 1,2,…n
    序列II b1,b2,…,b[n-2]
    在I中找出第一个不出现在II中数,显然是a1,连接边(a1, b1),在I中消去a1,在II中消
    去b1.如此步骤重复n-2次,序列I中两个数,构成最后一条边.

    以下是来自Matirx67的blog.

    ayley公式是说,一个完全图K_n有n^(n-2)棵生成树,换句话说n个节点的带标号的无根树有n^(n-2)个。Cayley公式的一个非常简单的证明,证明依赖于Prüfer编码,它是对带标号无根树的一种编码方式。
    给定一棵带标号的无根树,找出编号最小的叶子节点,写下与它相邻的节点的编号,然后删掉这个叶子节点。反复执行这个操作直到只剩两个节点为止。由于节点数n>2的树总存在叶子节点,因此一棵n个节点的无根树唯一地对应了一个长度为n-2的数列,数列中的每个数都在1到n的范围内。下面我们只需要说明,任何一个长为n-2、取值范围在1到n之间的数列都唯一地对应了一棵n个节点的无根树,这样我们的带标号无根树就和Prüfer编码之间形成一一对应的关系,Cayley公式便不证自明了。
    看到这,我建议自己划一划,结果就出来了(这句话是我的建议,非Matrix67原文)。
    注意到,如果一个节点A不是叶子节点,那么它至少有两条边;但在上述过程结束后,整个图只剩下一条边,因此节点A的至少一个相邻节点被去掉过,节点A的编号将会在这棵树对应的Prüfer编码中出现。反过来,在Prüfer编码中出现过的数字显然不可能是这棵树(初始时)的叶子。于是我们看到,没有在Prüfer编码中出现过的数字恰好就是这棵树(初始时)的叶子节点。找出没有出现过的数字中最小的那一个(比如④),它就是与Prüfer编码中第一个数所标识的节点(比如③)相邻的叶子。接下来,我们递归地考虑后面n-3位编码(别忘了编码总长是n-2):找出除④以外不在后n-3位编码中的最小的数(左图的例子中是⑦),将它连接到整个编码的第2个数所对应的节点上(例子中还是③)。再接下来,找出除④和⑦以外后n-4位编码中最小的不被包含的数,做同样的处理……依次把③⑧②⑤⑥与编码中第3、4、5、6、7位所表示的节点相连。最后,我们还有①和⑨没处理过,直接把它们俩连接起来就行了。由于没处理过的节点数总比剩下的编码长度大2,因此我们总能找到一个最小的没在剩余编码中出现的数,算法总能进行下去。这样,任何一个Prüfer编码都唯一地对应了一棵无根树,有多少个n-2位的Prüfer编码就有多少个带标号的无根树。

    一个有趣的推广是,n个节点的度依次为D1, D2, …, Dn的无根树共有(n-2)! / [ (D1-1)!(D2-1)!..(Dn-1)! ]个,因为此时Prüfer编码中的数字i恰好出现Di-1次。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    #define M 10003
    long long mod(int a,int b,int c)
    {
    	int t=1;
    	if(b==0)
    	return 1;
    	if(b==1)
    	return a%c;
    	t=mod(a,b>>1,c);
    	t=t*t%c;
    	if(b&1)
    	t=t*a%c;
    	return t;
    }
    int main()
    {
    	int t;
    	scanf("%d",&t);
    	while(t--)
    	{
    		int m;
    		scanf("%d",&m);
    		long long s=mod(m,m-2,M);
    		printf("%lld
    ",s);
    	}
    	return 0;
    }


  • 相关阅读:
    14.UA池和代理池
    13.scrapy框架的日志等级和请求传参
    12.scrapy框架之递归解析和post请求
    11.scrapy框架持久化存储
    10.scrapy框架简介和基础应用
    09.移动端数据爬取
    08.Python网络爬虫之图片懒加载技术、selenium和PhantomJS
    07.验证码处理
    vi编辑器
    tar 压缩命令
  • 原文地址:https://www.cnblogs.com/playboy307/p/5273503.html
Copyright © 2020-2023  润新知