4
29
2013
0

点分治

poj 1741 :男人八题23333

poj 2114:限制条件变成==k,该怎么弄怎么弄

省队互测题

BZOJ 1267 ←还没交

关于合并答案:

现在我们在点p,

p有各种孩子:b1,b2,b3,...,bn

首先可以得到他们的答案ans1...ansn

然后考虑经过p点的情形。

1)如果是要在限制Y下最大化XXXX(要满足可加性)

从一个子树出发,dfs出deepX情况下的最优解que[deep]

考虑这个最优解和前一颗线段树满足限制Y下的区间中的最优解的合并是否最优。

然后把这颗子树丢进线段树tree[deep](deep为关键字)

但是还有个单调性的做法:

当限制范围是L<=DIST<=R时

最大化tree[X]+que[Y] | L<=X+Y<=R,X,Y>=0

显然,如果X固定了,问题就变成求出que[L-X]到que[R-X]之间的最大值。

X单增,L-X,R-X也是单增,用单调队列维护就可以了。

nlogn->n  daze~啦啦啦啦啦比线段树好些多了23333

(某题解,差评!)

2)如果是要在限制条件Y下统计XXXX的个数

把条件转换成最好处理的,

利用单调性,类似统计逆序数的

统计一个子树下的答案,和所有子树下的答案……

然后该咋搞咋搞……

// 这只是一个简单的模板,在// ???填充代码……
#include <cstdio>
#include <cstdlib>
const int maxn = 100010;
const int maxm = 200010;
int n,l,r,mid;

struct node{
	int u,v,c;
	bool flag;
	node*next,*inv;
}E[maxm];int size = 0;

node * V[maxn];
int gravity[maxn];

int csize = 0;
int sum[maxn],balance[maxn];
bool inba[maxn];

int nsize = 0;

void callbalance(int root){
        nsize++;
	inba[root] = true;
	sum[root] = 1;
	for (node * it = V[root];it!=NULL; it = it->next){
		if (!t->flag){
			it->flag = it->inv->flag = true;
			callbalance(it->v);
			it->flag = it->inv->flag = false;
			sum[root]+=sum[it->v];
			balance[root] = (sum[it->v],balance[root]);
		}
	}
}

void callgravity(int root){
	csize = 0;
	memset(inba,0,sizeof(inba));
	node * p = V[root];

	callbalance(root);

	for(int i=1; i <= n; i++){
		if (inba[i]) balance[i] = max(nsize - sum[i] , balance[i]);
	}
	int mn = balance[root],int index = root;
	for(int i=1; i <= n; i++){
		if (inba[i]){ mn = balance[i]; index = i; }
	}

	gravity[root] = index;

	for (node * it = V[index];it!=NULL; it = it->next){
		if (!t->flag){
			it->flag = it->inv->flag = true;
			callbalance(it->v);
			it->flag = it->inv->flag = false;
		}
	}
}

int calc(int x){
	node * q = V[gravity[x]];
	int ans = 0;
	int rst = 0;
	for (node * it = q;it!=NULL;it = it->next){
		if (!t->flag){
			it->flag = true;
			it->inv->flag = true;
			ans = max(ans,calc(it->v));
			it->flag = false;
			it->inv->flag = false;
		}
	}
	// ???在这里合并。
	return max(ans,rst);
};
node* insert(int u,int v,int c,int g = 0,node *inv = NULL){
	node * p = &E[size++];
	p->u = u;p->v = v;p->c = c;p->g = g;p -> inv = inv?inv:insert(v,u,c,g,p);
	p->next = V[u];V[u]=p;
	return p;
}
int main(){
	scanf("%d%d%d",&n,&l,&r);
	for (int i = 0;i < n-1;i++)
	{
		int u,v,c;
		scanf("%d%d%d",&u,&v,&c);
		insert(u,v,c);
	};
	callgravity(1);

}
Category: 未分类 | Tags: 分治
4
21
2013
4

DP && 分治

uva10635:LCS转LIS

uva11825:区间dp,预处理区间大小。

uva:11825:状压dp

uva:10859:树状dp

la:4794:状压dp

1176: [Balkan2007]Mokia: cdq分治

noi2007cash: 同上……

lhx浅谈分治最后一个例题:

递归处理[l,r]。

每次处理的时候维护f[]=上一层的答案+[l,r]^1的答案。

处理到l==r的时候处理询问。

Category: OI | Tags: 动态规划
4
20
2013
12

Viterbi算法

今天我在翻DP的时候,意外的发现了这个有趣的东西:-D。

其实很简单……只是居然可以用Dp。而且能做的事情很多。

Category: OI | Tags: 动态规划 数学
4
18
2013
0

线性规划(某一类线性规划程序写法)

这个实现:

http://hi.baidu.com/__vani/item/19c2b226010fd4896e2cc345

是有问题的,只能在变量始终为0\1\-1的题里用

http://hi.baidu.com/nehzilrz/item/9fba95952db43b30336eebf7

这个通用一些……

注意各种变量的正负。

Yangff 20:23:37 
……
Yangff 20:23:40 
好吧&……
Yangff 20:23:43 
原来是不等式。。
Yangff 20:24:21 
等扥……
Yangff 20:24:23 
等等……
Yangff 20:24:44 
 这诡异的式子。。
wyl8899 20:24:58 
有什么问题吗..
wyl8899 20:25:16 
recall x[i]=b[i]-∑A[i][j]*x[j] , x[i]>=0 
Yangff 20:25:26 
不应该是x[i+n]么。。 
wyl8899 20:25:23 
哦.. 
wyl8899 20:25:29 
因为是虚拟的变量 
Yangff 20:25:47 
…… 
Yangff 20:25:50 
我知道是虚拟的。。 
Yangff 20:25:55 
看起来直接就没存了。。 
wyl8899 20:26:01 
恩.. 看起来是这个样子 
Yangff 20:26:10 
但是移动的时候会移动到啊。。这里就完全不理解了。。 
Yangff 20:26:38 
= =……我觉得省略了各种的正负号变换…… 
Yangff 20:26:50 
符号看的我快吐了。。 
wyl8899 20:26:52 
我也觉得..  
Yangff 20:29:27 
= =。。你问一下他,没有辅助变量的话……他在和谁松弛。。 
Yangff 20:29:36 
我是说pivot。。 
wyl8899 20:30:13 
这就是x[l]和x[e]的对换啊... 
Yangff 20:30:30 
对啊。 
Yangff 20:30:40 
但是问题是x[l]和x[e]都是当前已选定的。。 
wyl8899 20:30:33 
辅助变量是存在的.. 
Yangff 20:30:42 
换来干嘛。 
Yangff 20:30:44 
额= =? 
wyl8899 20:30:43 
在你的脑海当中 
Yangff 20:31:00 
但是他没有存辅助变量的系数啊。。 
wyl8899 20:31:20 
一开始
x[l+n]=a[l][0]+∑a[i][j]*x[j]>=0对吧 
Yangff 20:31:34 
嗯…… 
wyl8899 20:31:32 
系数根本就是1嘛.. 干嘛要存下来 
Yangff 20:31:49 
换了就不一定是1了啊。。 
wyl8899 20:31:44 
然后来看看那个x[e] 
wyl8899 20:32:12 
由于pivot的条件,已经保证了A[l][e]>0 
wyl8899 20:32:20 
换句话说a[l][e]=-1 
Yangff 20:32:38 
= =? 
wyl8899 20:32:41 
(假定只有1/0/-1的情况 
Yangff 20:33:02 
a[l][e]>0所以a[l][e]=-1? 
wyl8899 20:33:13 
A[l][e]>0  ,  a[l][e]<0  ,  a[l][e]=-1  
Yangff 20:33:27 
哦哦 
wyl8899 20:33:26 
于是我们移一下项.. 
wyl8899 20:33:51 
x[l+n]=a[l][0]+∑(j!=e)a[i][j]*x[j]+a[l][e]*x[e] 
wyl8899 20:34:19 
x[e]=a[l][0]+∑(j!=e)a[i][j]*x[j]+(-1)x[l+n]>=0 
Yangff 20:35:36 
嗯。。 
wyl8899 20:35:33 
给x[l+n]起个新的名字,叫做x[e]
给x[e]起个新的名字,叫做x[l+n] 
wyl8899 20:36:02 
x[l+n]=a[l][0]+∑a[i][j]*x[j] , 只要a[l][e]=-1就完成任务了 
Yangff 20:36:58 
等等…… 
Yangff 20:37:09 
难道不要把原来的x[l+n]移过去吗? 
Yangff 20:37:16 
移到右边 
wyl8899 20:37:16 
移了啊 
wyl8899 20:37:37 
很显眼的(-1)x[l+n] 
Yangff 20:38:00 
a[l][e]=-1只是把x[e]移到左边啊。。 
Yangff 20:38:14 
左边的l(l+n)不应该移到右边吗? 
wyl8899 20:38:25 
a[l][e]=-1是在把x[l+n]移到右边去啊 
Yangff 20:38:49 
0 0? 
wyl8899 20:38:42 
x[e]成为基本变量了以后系数永远是1 不存 
Yangff 20:39:00 
对。 
wyl8899 20:39:06 
所以这里我们设定的是x[l+n]在x[e]的等式里的系数 
wyl8899 20:39:31 
但是由于他们已经调换名字了.. 所以是a[l][e]=-1 
Yangff 20:39:45 
等等……也就是说a[l]存的是原来的a[e]经过改变后的系数? 
Yangff 20:40:05 
a[e]存的是移项后的a[l]? 
wyl8899 20:40:04 
对对对对 
Yangff 20:40:16 
哦! 
wyl8899 20:40:17 
有没有觉得很碉堡 
wyl8899 20:40:31 
所以从头到尾都只有m个(不)等式 
Yangff 20:40:47 
也就是说,永远保证下标是等式左边的下标? 
Yangff 20:40:55 
果然碉堡。。
wyl8899 20:40:57 
但是.. 输出方案就要麻烦一些了
Yangff 20:41:12 
= =。。
Yangff 20:41:31 
等等……
Yangff 20:41:35 
这样好像还是有点问题。。
wyl8899 20:41:57 
呃.. 哪里有问题?
Yangff 20:42:43 
如果只保存了n(也就是原始约束个数)个不等式的话,去哪里和新增加的辅助变量交换。。
Yangff 20:43:05 
既然下标一定是等式左边的下标
wyl8899 20:43:59 
辅助变量.. 你是说n+1..n+m这些吗
Yangff 20:44:12 
嗯。
Yangff 20:44:18 
因为是要和他们交换啊。
wyl8899 20:44:19 
他们从头到尾都只存在于你的脑海里
Yangff 20:44:33 
^
Yangff 20:44:44 
那怎么枚举。。
wyl8899 20:45:04 
你是说在确定PIVOT的对象的环节?
Yangff 20:45:16 
毕竟他们也可能被选中啊。。
wyl8899 20:45:16 
被选中?
Yangff 20:45:37 
就是说,下标为n+1,...n+m的变量。
Yangff 20:45:52 
也可能变成非基变量啊。。
Yangff 20:46:32 
如果不存他们的话,你的下标只能在0~n之间变。。
wyl8899 20:46:35 
所以说是下标永久对换啊
wyl8899 20:46:38 
这么说吧.. 继续前面的PIVOT(l,e)
wyl8899 20:46:52 
a[e][]存了移项以后的a[l][]
wyl8899 20:46:58 
不对..
Yangff 20:47:10 
我知道下标是永久对换的。但是你换的范围只有0~n
Yangff 20:47:16 
1~n
Yangff 20:47:28 
那不就没有意义了,我本来就是这n个不等式的。。
wyl8899 20:47:24 
我不懂应该怎么解释清楚..
wyl8899 20:47:30 
不管你怎么PIVOT
Yangff 20:47:41 
><..
wyl8899 20:47:36 
永远只有n个不等式
Yangff 20:47:59 
好吧。。
Yangff 20:48:01 
换句话说。
Yangff 20:48:56 
一个x[n+2](基)和x[2](非基)在PIVOT之后的下标分别是什么(其中n+2是不占在a数组下标的)
wyl8899 20:49:53 
x[2]永久的... 消失了
x[n+2]取而代之
Yangff 20:50:51 
也就是说……系数是有n+2的位置的?
Yangff 20:51:00 
只是不等式没有?
wyl8899 20:51:39 
不是啊...
wyl8899 20:51:46 
x[2]不是已经消失了吗..
Yangff 20:52:03 
嗯。。
wyl8899 20:52:05 
所以现在x[n+2]完全的成为了x[2]
Yangff 20:52:16 
哦!
Yangff 20:53:35 
我是说在系数中。。
wyl8899 20:54:00 
呃... 在这次PIVOT之后 一切a[][2]都指的是x[2] 也就是原来的x[n+2]
Yangff 20:54:16 
x[l]=a[l][0]+∑a[i][j](这里有没有n+2的位置)*x[j]

Yangff 20:54:19 
哦。。
wyl8899 20:54:30 
在PIVOT的后半部分已经完整的完成了这个取而代之的工作
Yangff 20:54:47 
我知道了。。
wyl8899 20:56:03 
可以写一份《论如何读懂一类单纯形代码》来造福人类了...
Yangff 20:56:58 
那怎么知道a[i][..]带边的左边的x的下标……难道也直接换成x[i]?
Yangff 20:57:28 
把x[n+2]直接取代x[2]的一切位置,名字,下标?
wyl8899 20:58:17 
恩
Yangff 20:58:30 
*以及在别的不等式中的x[2]也换成x[n+2]?
Yangff 20:58:32 
好啊并。。
Yangff 20:58:34 
好吧。。
Yangff 20:58:35 
我懂了。。
Yangff 21:00:00 
那么……
 
这一行的循环范围并没有超过不等式的数量……
Yangff 21:00:13 
他是怎么把辅助的不等式考虑进来的……
Yangff 21:00:23 
还是说这个m=n+m?
wyl8899 21:01:11 
这一行是在选择一个在目标函数中系数为负的非基本变量吧
Yangff 21:01:37 
嗯。。 
wyl8899 21:01:48 
那关基本变量(你愿意叫他辅助变量也可以)什么事.. 
Yangff 21:02:01 
说错了= = 
Yangff 21:02:03 
下面那个= = 
Yangff 21:02:12 
他只循环到n啊。。 
wyl8899 21:02:12 
因为只有n个不等式对吧.. 
Yangff 21:02:24 
嗯。。。 
wyl8899 21:02:26 
那就没事了啊.. 这不是考虑清楚了么 
Yangff 21:02:43 
= =。。 
Yangff 21:02:48 
总共有n+m个不等式啊。。 
Yangff 21:02:55 
只是当前有效的n个。。 
Yangff 21:03:01 
别的都被这n个确定了啊。。 
Yangff 21:03:16 
但是交换的时候不是应该从m这里拿吗。。 
Yangff 21:03:22 
(好吧,我n,m都快乱了) 
wyl8899 21:03:29 
那就明确一下吧 n是约束个数 m是变量个数 
Yangff 21:03:41 
嗯。。 
wyl8899 21:03:39 
*非基本变量个数 
Yangff 21:03:55 
嗯。。 
wyl8899 21:03:58 
那n+m个不等式... 
Yangff 21:04:10 
嗯。。 
Yangff 21:04:15 
*-* 
wyl8899 21:04:08 
有n个已经被存下来了 
Yangff 21:04:21 
嗯 
wyl8899 21:04:23 
其余的m个都是非负性限制不是吗.. 
Yangff 21:04:40 
嗯 
wyl8899 21:04:38 
所以还有什么问题呢.. 
wyl8899 21:04:59 
不管这个PIVOT怎么乱来 松弛型的形态都没有改变 
Yangff 21:06:41 
但是…… 
Yangff 21:06:48 
他这里怎么看都是在自己和自己松弛啊。。 
Yangff 21:06:52 
pivot 
wyl8899 21:07:55 
啊..  
Yangff 21:08:46 
l∈[1,n]
e∈[1,m]
如果我要和n+m松弛怎么办。。 
Yangff 21:08:48 
pivot 
Yangff 21:09:11 
这里l永远不可能是n+m啊。 
Yangff 21:09:25 
但是真正操作的时候是有可能用到的啊。。 
wyl8899 21:09:35 
你是说l的取值范围啊 
Yangff 21:09:48 
嗯! 
Yangff 21:10:05 
毕竟l决定了e将来的下标 
wyl8899 21:09:59 
l是1..n就取遍了n个非基本变量啊 
wyl8899 21:10:10 
不对.. 
wyl8899 21:10:14 
n个基本变量 
Yangff 21:10:36 
但是pivot里面不管是不是非基变量,都是直接a[l]直接取了啊。。 
Yangff 21:10:58 
但是a[l]显然是非基本变量啊 
Yangff 21:11:09 
a[l+n](不存在)才是基本变量吧。 
wyl8899 21:11:30 
但是a[l][]保存的是(x[l+n]=)a[l][]+∑a[l][j]*x[j]不是么 
Yangff 21:11:44 
!! 
Yangff 21:11:47 
懂了! 
Yangff 21:11:59 
太感谢了……*_* 
Yangff 21:12:19 
(这写法大坑啊…… 
wyl8899 21:13:03 
所以我说应该可以写一份《论如何读懂一类单纯形代码》来造福人类了... 
Yangff 21:13:26 
同意。。 
Yangff 21:15:51 
稍等……如果这样的话……
a[l][e] = -1;后面不应该跟一个
a[l][l] = 1;吗? 
wyl8899 21:16:16 
a[l][l]存的是啥? 
Yangff 21:16:28 
哦哦哦。。 
Yangff 21:16:31 
我看错了= = 
Yangff 21:19:18 
/**
  e成为基变量,位置为n+l
  n+l成为非基变量,位置为e
**/
inline pivot(int l,int e) 
Yangff 21:19:26 
所以这是这个函数的意思么。。 
wyl8899 21:19:32 
恩... 
Yangff 21:19:46 
大坑/A\ 
wyl8899 21:19:47 
 绝对的大坑...

uva10489

usaco ditch

Category: 未分类 | Tags:
4
15
2013
0

【转】FFT

#include <iostream>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int maxh = 10,maxn = 1<<maxh,P = 12289;
const int g=10302,ig = 8974,ninv = 12277;
typedef long long ll;
struct fft{
    ll omg[maxn],iomg[maxn],inv[maxn];
    void initialize(){
        for(int i=0;i<maxn;i++) inv[i] = getinv(i);
        omg[0] = 1,iomg[0] = 1;
        for(int i=1;i<maxn;i++)
            omg[i] = omg[i-1]*g%P,iomg[i] = iomg[i-1]*ig%P;
    }
    ll getinv(ll x){
        ll ans = 0;
        for(int i=0;i<maxh;i++)
            ans |= (x>>i&1)<<maxh-i-1;
        return ans;
    }
    ll f[2][maxn];
    void ft(ll *o,ll *cof,ll *output){
        for(int i=0;i<maxn;i++) f[0][i] = cof[inv[i]];
        for(int h=1;h<=maxh;h++)
            for(int i=0;i<maxn;i++)
                f[h&1][i] = (f[h&1^1][~(1<<h-1)&i]+o[i<<maxh-h&maxn-1]*f[h&1^1][i|1<<h-1]%P)%P;
        for(int i=0;i<maxn;i++) output[i] = f[maxh&1][i];
    }void dft(ll *cof,ll *output){ft(omg,cof,output);}
    void idft(ll *cof,ll *output){ft(iomg,cof,output);for(int i=0;i<maxn;i++) output[i] = output[i]*ninv%P;}
}F;
ll cof1[maxn],cof2[maxn];
char input[maxn],input2[maxn];
int n;
void Init(){
    int len;
    gets(input2);len = strlen(input2);
    for(int i=0;i<len;i++) input[i] = input2[len-i-1];
    for(int i=0;i<len;i++) cof1[i] = input[i]-'0';
    gets(input2);len = strlen(input2);
    for(int i=0;i<len;i++) input[i] = input2[len-i-1];
    for(int i=0;i<len;i++) cof2[i] = input[i]-'0';
}
void solve(){
    F.initialize();
    F.dft(cof1,cof1);F.dft(cof2,cof2);
    for(int i=0;i<maxn;i++) cof1[i] = cof1[i]*cof2[i]%P;
    F.idft(cof1,cof1);
    int jw = 0;
    for(int i=0;i<maxn;i++){
        cof1[i] += jw%10,jw/=10;
        jw+=cof1[i]/10,cof1[i]%=10;
    }
    bool flag = false;
    for(int i=maxn-1;i>=0;i--){
        if(cof1[i]!=0) flag = true;
        if(flag) printf("%c",cof1[i]+'0');
    }
}
int main(){
    freopen("test.in","r",stdin);
    freopen("test.out","w",stdout);
 
    Init();
    solve();
 
    fclose(stdin);
    fclose(stdout);
    return 0;
}
Category: OI | Tags: 数学
4
13
2013
36

Google Code Jam 2013 - 资格赛

A、B水题。。

C有点坑爹……

		if (palindromes(i) && palindromes((long long)i*i)){
			fairandsquare[fs++] = i*i;
		}

然后我就傻逼了。

打了个表……

然后会发现,去掉长度=1的。

长度为偶数的:

11 22

1001 1111 2002

100001 101101 110011 111111 200002 

10000001 10011001 10100101 10111101 11000011 11011011 11100111 11111111 20000002 

长度为奇数的:

101 111 121 202 212 

10001 10101 10201 11011 11111 11211 20002 20102

1000001 1001001 1002001 1010101 1011101 1012101 1100011 1101011 1102011 1110111 1111111 2000002 2001002 

100000001 100010001 100020001 100101001 
100111001 100121001 101000101 101010101 
101020101 101101101 101111101 110000011 
110010011 110020011 110101011 110111011 
111000111 111010111 111101111 111111111 
200000002 200010002
当头尾=2的时候就两种情况……
当头尾=1的时候,分别中间从长度-2~长度=1
但是其中有一部分是不可行的……特判掉就好……
要直接构造也可以……不过……麻烦。
 
 
Category: OI | Tags: GCJ2013
4
12
2013
0

【整理中】最大流

黑色已过
网络流:
基础
poj1149: 给你一堆猪圈,以及一些买猪的人,每个买猪的人操作时可以打开一些猪圈,他最多买走一定数量的猪。最后,在他操作结束后,可以任意移动已经打开的猪圈里面的猪,关上猪圈,继续下一个人。问最多能卖多少猪。
sol:
考虑每次交易和所有猪圈构成网格,去除多余的节点,得到:
S->第一个在这个猪圈买猪的人,容量是这个猪圈猪的数量。合并冗余的边。
如果一个猪圈一共有n次交易,则第i个顾客往i+1连一条边。
顾客往T连一条容量为购买限制的边。
hdu1569: m是列n是行……
带上下界的网络流
  1. 无源无汇带上下界网络流:
    • 求出一组解,使得对于任意一条边满足C(u,v)∈[L,R],ΣC(u,v) - ΣC(v,p) = 0 
    • sgu194给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质。并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li。
    • sol:先把每条边的容量Ri-Li,也就是强制流入Li。
    • 重新计算每个点的入流量-出流量
    • 显然,如果一个点的入流量!=出流量,就需要在Li的基础上加上delta。
    • 为了分配delta,一个显然的事实就是,通过一个超级源给入流量>出流量的点,入流量-出流量的流入,(也就是在满流的情况下将会全部从这里流出去,这样出流量就平衡了)
    • 同理,给入流量<出流量的点,出流量-入流量的流出空间到超级汇
  2. 有源有汇带上下界网络流:
    • 求出一组解,是的对除了S和T以外的点,满足以上流量守恒性质
    • zoj3229 Shoot the Bullet:一个屌丝给m个女神拍照,计划拍照n天,每一天屌丝最多个C个女神拍照,每天拍照数不能超过D张,而且给每个女神i拍照有数量限制[Li,Ri],对于每个女神n天的拍照总和不能超过Gi,如果有解求屌丝最多能拍多少张照,并求每天给对应女神拍多少张照;否则输出-1。
    • 加入T到S的一条容量无穷大的边,同上面方法做,加入新源汇SS,TT,然后去掉这条边和SS,TT,再跑一次S到T的最大流。
    • 引用:当有可行流时,删除超级源点ss和超级终点dd,再对(s,d)进行一次最大流,此时得到的maxflow则为题目的解。为什么呢?因为第一次maxflow()只是求得所有满足下界的流量,而残留网络(s,d)路上还有许多自由流(没有和超级源点和超级汇点连接的边)没有流满,所有最终得到的maxflow=(第一次流满下界的流+第二次能流通的自由流)。
  3. 可行流、最小费用可行流:
    • 如果只要可行流,则不需要第二次操作。
    • 如果要最小费用,则第二次操作增广时,出现正数停止。
    • zju2314 sgu176

无向图最小割

Stoer Wagner算法:

maximum_adjacency_search:

1.设W[x]表示x到集合W中所有元素的距离和

2.不断地把W[x]最大的点加入集合W,更新W[x]

3.记录最后加入的两个点pre和cur。

stoer_wagner:

1.重复V-1次maximum_adjacency_search

2.每次操作后,如果W[cur]<ans则更新ans

3.将cur合并到pre,对(u,v,w)∈cur,使得(pre,v,wp)变为(pre,v,wp+w)

4.回到1 。

poj2914:裸题

未完待续。。

题目:

志愿者招募

>  每种志愿者i可以服务[Li,Ri]的时间,需要支付Ci的费用。

> 每天至少需要P[i]的志愿者

---------------------------------------------------------------------------

> 设第i中志愿者雇佣了X[i]个。

> X[0]+X[1]+X[2] >= P[1]

> X[1]+X[2] >=P[2]

> X[3]+X[4]+X[5]>=P[3]

……

转化为等式上下相减,发现右边的常数和为0 。每个X[i]在上下一正一负。

把每个等式看成一个节点。

如果常数>0则从S连接到方程,容量为常数

<0则从点到T连-常数

X[i]在j中为正,k中为负,从j->k

Y[i]同理

http://www.byvoid.com/blog/noi-2008-employee/

 

做题:

http://hi.baidu.com/daizhy_acm/item/5c7e60dfcf33a1f8ca0c393e

poj2391:给定n个牛棚,牛棚之间连带权边。每个牛棚有数量的上限,问最少需要多少时间可以调整牛不被淋湿。

sol:对牛棚拆点,S->u,容量奶牛数量。u->u'容量无限u'->T容量为容纳限制

二分上界,添加(u,v') (v,u')当u到v的最短路小于上界。

poj1087:给定一些插座、电器、转换器。电器有插座要求,插座只能用一次,转换器可以无限使用,问最多适配多少个电器。

sol:读入好烦……题目好晕,其实很水……S->电器(1);电器->插座种类(1);插座种类->该种类插座(1);插座种类->插座种类(INF);插座->汇(1)

其实,把插座种类和插座合并,然后向汇连该种类数量也是可以的。。

参考:

http://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html

http://blog.csdn.net/pouy94/article/details/6628521

http://blog.sina.com.cn/s/blog_700906660100v7vb.html

http://hi.baidu.com/zhanggmcn/item/e119cc25adb5a88d9c63d1e7

http://akheyun.blog.163.com/blog/static/138249276201032946358/

http://www.byvoid.com/blog/noi-2008-employee/

Category: OI | Tags: 图论
4
12
2013
2

【转】各种图论模型及其解答

转载自:http://blog.chinaunix.net/uid-9112803-id-411340.html

摘要:

本文用另一种思路重新组织《图论及其应用》相关知识。首先,用通俗化语言阐述了如何对事物间联系的问题进行图论建模;接着从现实例子出发,给出各种典型图论模型,每种图论模型对应于图论一个重要内容;再者,介绍相关知识对上述提到的图论模型涉及的问题进行解答;最后,补充一些图论其他知识,包括图论分支、易混概念。

 

符号约定:

Q(Question)表示对问题描述,M(Modeling)表示数学建模过程,A(Answer)表示原问题转化为何种图论问题。

 

一、引言

图论是研究点、线间关系的一门学科,属于应用数学的一部分。现实生活中,凡是涉及到事物间的关系,都可以抽象为图论模型。点表示事物,连线表示事物间的联系。整个求解过程如下:

原问题——>图论建模——>运用图论相关理论求解——>转化为原问题的解

整个过程关键在于图论建模,所谓图论建模,就是明确点表示什么,连线表示什么,原问题转化为图论中的什么问题。存在以下两种情况:

①若事物间联系是可逆的(比如双行道,朋友),则抽象成无向图

②若事物间联系是不可逆的(比如单行道,状态转化不可逆),则抽象成有向图

如果需要进一步刻画事物间的联系(比如城市间的距离),就给连线赋一个权值,从而抽象成赋值图

综上,根据实际问题,可建模成下列图论模型的一种:无向赋权图、有向赋权图、无向非赋权图、有向非赋权图。

例1.宴会定理:任何一宴会中,一定存在两个人有相同的数量朋友

M:点表示人,连线表示当且仅当该两个人是朋友

A:问题转化为任何一个图一定存在两个顶点的度相等

 

二、图论模型

接下来介绍若干典型的图论模型,每种模型几乎对应于图论的一个重要内容,这些内容将在第三章进行讨论,也就给出了这些模型的解答思路。

2.1 偶图模型

凡涉及两类事物间的联系(即只考虑两类事物间的联系,而不考虑同类事物间的联系),均可抽象成偶图模型。作图时,将两类事物分成两行或者两列。这类模型通常被包含在后续的模型中,但因许多现实问题可抽象成该模型,所以单列出来讨论。

(1) 仓库与销售间

M:点代表仓库或销售点,连线代表仓库与销售店间的关联

(2) 上课安排问题

Q:学校有6位教师将开设6门课程。六位教师的代号是Xi(i=1,2,3,4,5,6),六门课程代号是Yi (i=1,2,3,4,5,6)。已知,教师X1能够胜任课程Y2和Y3;教师X2能够胜任课程Y4和Y5;教师X3能够胜任课程Y2;教师X4能够胜任课程Y6和Y3;教师Y5能够胜任课程Y1和Y6;教师X6能够胜任课程Y5和Y6。

M:点表示教师或者课程,连线表示当且仅当该教师能胜任该课程

2.2 最短路模型

凡涉及到最小状态转换问题,均可转化为最短路模型。点表示允许的状态,连线表示状态的转换(可逆与不可逆分别对应于无向图、有向图)。

(1) 最短航线

M:点表示城市,连线表示当且仅当两城市有直达航线,并在该线上注明两城市的距离,即权值

A:问题转化为求两点间的最短路径

(2) 状态转换

Q:某两人有一只8升的酒壶装满了酒,还有两只空壶,分别为5升和3升。求最少的操作次数能均分酒。

M:设x1,x2,x3分别表示8,5,3升酒壶中的酒量,则

点表示组合(x1,x2,x3) ,连线表示当且仅当可通过倒酒的方式相互变换

A:问题转化为在该图中求点(8,0,0)到点(4,4,0)的一条最短路

(3) 狼羊菜渡河

Q:在一河岸有狼,羊和卷心菜。摆渡人要将它们渡过河去,由于船太小,每次只能载一样东西。由于狼羊,羊卷心菜不能单独相处。问摆渡人至少要多少次才能将其渡过河?

M:但是以下组合不能允许出现:狼羊菜,羊菜,狼羊,人,人狼,人菜,共6种。岸上只能允许出现10种组合:人狼羊菜,人狼羊,人狼菜,人羊,空,菜,羊,狼,狼菜,人羊菜。

点表示可允许的组合,连线当且仅当两种情况可用载人(或加一物)的渡船相互转变。

A:问题转化为求由顶点“人狼羊菜”到顶点“空”的一条最短路。 

2.3 最小生成树模型

道路铺设

Q:道路铺设,使得任意两个地方均可达,并且费用最小

M:点表示工厂(假设是工厂),任意两点连线,并标出铺设需要的费用

A:问题转化为求该图的最小生成树

2.4 欧拉图模型

通俗地讲,G是欧拉图当且仅当G存在经过每条边恰好一次,并且回到起始点的迹。

(1) 哥尼斯堡七桥问题

Q:能否从一点出发,走遍7座桥,且通过每座桥恰好一次,最后仍回到起始地点

M:点表示陆地,连线表示桥

A:问题转化为G是否存在E图

(2) 中国邮递员问题

Q:邮递员必须走过他投递范围内的每一条街道至少一次,选择一条尽可能短的路线

M:点表示路口,连线表示当且仅当两路口有直达街道

A:若G是E图,通过Fleury算法构造Euler环游,即为所求。否则,按一定规则添加重复边,再用Fleury算法构造Euler环游。

2.5 哈密尔顿圈模型

(1) 旅行售货员问题——TSP

一售货员要到若干城市去售货,每座城市只经历一次,问如何安排行走路线,使其行走的总路程最短。

例子:

Q:一电脑代理商要从她所在城市出发,乘飞机去六个城市,然后回到出发点,如果要求每个城市只经历一次,能否办到?给出行走方案。

M:点表示城市,连线表示两城市有直达航线

A:该图是否存在H圈

(2) 圆桌会议座位安排

Q:若干人围圆周开会,每个人会不同的语言,如何安排座位,使得每个人能够和他身边的交流

M:点表示人,连线表示当且仅当两个人能交流,即至少会同一种语言。(可能你一下子想到的偶图模型,的确该问题可以抽象成偶图模型,但很难转化为图论问题)

A:给出该图的一个H圈

2.6 匹配模型

(1) 旅游座位安排

Q:有一个旅行团要组织一批人去旅游,其中一些人是朋友他们要乘坐公共汽车去,而车上的位子是成对的。因此为了让大家旅途更愉快,旅行团负责人需要将成对的朋友安排在一起。给出一种安排方案。

M:点表示旅行团的人,连线表示当且仅当两人是朋友

A:求该图的最大匹配

(2) 研究生找工作

Q:学生能找到理想工作吗?

M:点表示研究生或者工作,连线表示当且仅当学生申请了该工作

A:问题转化为求饱和每个顶点的一个匹配,即完美匹配

(3) 最优分派问题

M:点表示工作或者人员,构造完全偶图,边的权值表示该工人做此份工作的效率

A:问题转化为求该图的最优匹配

2.7 平面图模型

平面模型可以这样理解,交通网络,使得不交叉,且无需修高架桥、隧道(这里的隧道显然跟山洞不同)

(1) 电路板设计问题

Q: 连接电路元件间的导线间不能交叉。否则,当绝缘层破损时,会出现短路故障。

M;点表示电路元器件,连线表示元器件间的连接

A;该图是否可平面

(2) 景区空调管道的设计

M:点表示景区,连线表示当且仅当两景点间要铺设空调管道

A:能否把上图画在平面上,使得边不会相互交叉?

(3) 3间房子和3种设施问题

Q:要求把3种公用设施(煤气,水和电)分别用煤气管道、水管和电线连接到3间房子里,要求任何一根线或管道不与另外的线或管道相交,能否办到?

M:点表示公用设施或者房子,连线表示该类公用设施连接到该房子

A:抽象出来的图是否可平面嵌入

2.8 着色模型

点着色问题对应于顶点集合的一种划分方式,对应于分类问题。边着色对应于边集合的一种划分方式,也对应于分类问题。区分点着色模型和边着色模型,主要在于抽象出来的模型,是相邻的顶点还是相邻的边不能着同一种颜色。

(1) 点着色模型

① 考试时间安排

Q:使得学生们不会有相互冲突的考试,最小安排数

M:点表示待考的课程,连线表示至少有一个学生同时选择这两门课

A:问题转化为求该图的点色数(把互不冲突的课程、考试安排在同一个时间段完成)

② 课程安排问题

Q: 学生选择课程中,使得学生选课不会发生冲突,如何制订一张课时数尽可能小少的课表

M:点表示课程,连线表示当且仅当有某个学生同时选了这两门课程

A:问题转化为求该图的点色数

③ 交通灯的相位设置问题

Q:为了(最终)让所有的车辆都能够安全通过路口,对于交通灯来说,所需要的相位的最小数是多少

M:点表示车道,连线当且仅当两个车道上的车不能同时安全地进入路口

A:问题转化为求该图的点色数

(2)边着色模型

① 排课表问题

Q:设有m位教师,n个班级,其中教师xi要给班级yj上pij节课。求如何在最少节次排完所有课。

M:令X={x1,x2,…,xm}, Y={y1,y2,…,yn},xi与yj间连pij条边,得偶图G=(X, Y)。

A:问题转化为求该图的边着色数

(2) 比赛安排问题

Q:最少天完成比赛

M:点表示参赛人,连线当且仅当两人有比赛

A:问题转化为求一种最优边着色,即用最少色数进行正常边着色

2.9 覆盖模型

覆盖模型,对应于控制问题,通俗地讲点覆盖对应于用最少的点来控制所有边(即任一边至少有一个顶点在点独立集中),边覆盖对应于用最少的边控制所有的点。均对应于控制问题。

(1) 哨站设计

Q:城市设置哨岗,使得哨兵能监管所有街道的最少哨岗数

M:点表示交叉口,连线表示存在直达街道

A:问题转化为求该图的点覆盖

2.10 强连通性定向图模型

(1) 城市交通网设计问题

Q:一座城市为某种需要,要把所有街道改为单行道,使得人们在任意两个位置都可以相互到达。如何设计单行道方向

M:顶点表示街道交叉口,连线当且仅当存在直达街道

A:问题等价于在模型图中给出其强连通定向

(2) 竞赛图

M:循环比赛的结果可以用所谓的“竞赛图”来表示。u队战胜了v队,则由点u向v画一条有向边。显然,“竞赛图”是完全图的一种定向图。

 

三、模型求解

现针对上述的模型给出求解过程,每个模型几乎对应于图论的一个主要内容。

3.1 偶图模型

正如上文所说,偶图模型只是建模方式,并没有与直接问题关联起来。

3.2 最短路算法

(1) Dantjig算法——顶点标号法

在已选定的集合A的临近点集合B(不包含A集合的点),选择符合条件(选择的点不会构成回路,边权值最小)的点加入集合A。迭代,直到终点出现在集合A中。
3.3 最小生成树算法
(1) Kruskal(克鲁斯克尔)算法

从G中的最小边开始,进行避圈式扩张。从符合扩展边(新加入的边不会构成回路)选择权值最小的边进行扩展。

(2) 管梅谷的破圈法

不断破圈(从赋权图G中没有圈为止,最后剩下的G的子图为G的最小生成树。
(3)  Prim算法
    关联的且权值最小的边作为最小生成树的第一条边e1。在接下来的边e2,e3,<span times="" new="" roman";mso-hansi-font-family:="" roman""="" style="word-wrap: break-word; font-size: 12pt; font-family: 宋体;">…,en-1 ,在与一条已经选取的边只有一个公共端点的的所有边中,选取权值最小的边。

3.4 Euler环游

(1) Euler环游判定

连通图G是Euler图 <==> G的每个顶点的度为偶数

连通图G有Euler迹 <==> G最多有两个奇点
(1) 构造欧拉环游(Fleury算法)
    该算法解决了在欧拉图中求出一条具体欧拉环游的方法。方法是尽可能避割边行走。
(2) 最优环游算法(中国邮路问题)
    若G是Euler图,则G的任何环游都是最优环游(最优环游是指在具有非负权的赋权连通图中找出一条最小权的环游)。

若G不是Euler图,则G的任何环游,通过某些边不止一次,通过以下方法求

添加重复边(其一,每条边最多重复一次,得到一个Euler多重图;其二,在该多重图的每一个圈上,如果重复边的总权值大于该圈权值的一半,则交换重复边与不重复边),而后Fleury算法求得。
3.5 Hamilton

(1) H图判定

H图判定至今没有平凡的充要条件,不过可以通过如下定理辅助判断。

必要条件

G是H图 ==> 对于V的每个非空真子集S,均有ω(G-S)≤|S|,即若去k个点,得到连通分支数比k大,则不是H图(逆否命题)。(显然有割点的图不是H图)

充分条件

① 设G是n(n≥)阶简单图,δ≥n/2  ==> G是H图

② G是简单图,对于任意不相邻的顶点,满足d(u)+d(v)≥n,G是H图 <==> G+uv是H图

③ G是H图 <==> G的闭包是H图 (若G的闭包是完全图,则G是H图。但一个图的闭包不一定是H图)

闭包构造过程:将度数之和≥图的顶点个数的非邻接顶点对递归连接起来,直到不再有这样的顶点对存在。

(2) 最优H圈

在一个赋权完全图中,找出一个有最小权的H图,称这个圈为最优H圈。目前没有有效算法,但可以通过如下近似算法求得近似值:

首先求出一个H圈,通过替换边不断改善上界。通过求最小生成树获得其下界。

3.6 匹配模型

(1)匹配判定

①最大匹配判定:

G的匹配M是最大匹配 <==> G不包含M可扩充路

② 偶图匹配判定

设G为具有二分类(X,Y)的偶图,对于X的每个子集S ,G包含饱和X的每个顶点的匹配 <==> |N(S)|≥|S|

G是k正则偶图 ==> G有完美匹配

在偶图中,最大匹配的边数等于最小覆盖的顶点数

③ 完美匹配判定

G有完美匹配 <==> 对于V的每个非空真子集S,奇分支数ο(G-S)≤|S|

每个没有割边的3正则图都有完美匹配

G有完美匹配 <==> G有1因子 (图的一个1因子的边集等价于图的一个完美匹配)

④ 1-因子分解

完全图K2n是1-可因子化 (除2n外,其余的每个数按箭头方向移动一个位置,在每个位置,同一行的两点邻接就得到一个1因子)

任一正则偶图是1-可因子化 (不断减去完美匹配的方式求得所有1因子)

任一个具有H圈的3正则图是1-可因子化 (一个偶数个顶点的H圈可以分解为两个1-因子的并)

若3正则图有割边,则不可1-因子分解

(2)匈牙利算法——寻找偶图的最大匹配

从任一匹配M开始,若M饱和X中的每一个顶点,则M即为所求。否则,从在X在找一个非饱和点u,通过构造扎根于u的M交错树来寻找一条可扩路。交换边,得到一个更大的匹配。
(3)最优匹配(最优分派问题)

最优匹配即在赋权完全偶图中寻找一个具有最大权的完美匹配。可以通过Kuhn-Munkres最优匹配算法进行求解,该算法采用顶点标号修改策略。

3.7 平面性模型

(1)平面性判定

① 对于简单图G=(n, m),如果m>3n-6,则G是非可平面的;
② 对于连通图G=(n, m),如果每个面次数至少为l≥3,且m>(n-2)l/(l-2),则G是非可平面
③ G是可平面的 <==> G不含有与K5或K3,3同胚的子图 (库拉托斯基定理)
④ G是可平面的 <==> G不含有能够收缩成K5或K3,3的子图 (瓦格纳定理)
⑤ 通过平面性算法判定

⑥ 观察法判断,试图通过移动边,判断是否可平面

(2) 平面性算法(DMP算法)

3.8 着色模型

(1) 求点色数

① 任意的图G,均有χ≤Δ+1

② G是简单连通图,且G既不是完全图也不是奇圈,则χ≤Δ

③ G是非空简单图,则χ≤Δ2+1 (找出所有顶点度≥其相邻的顶点度 的顶点,在余下的顶点中找最大度的点,即为次大度,不等同于第二大度)

④ G是非空简单图,若G中度数最大的点互不相邻,则χ≤Δ

⑤ 对任意的平面图,均有χ≤5

⑥ 通过色多项式求得,即最小k使得Pk(G)不等于0

    上面的各种方法都很繁琐,仅给出了上界。在实际求解过程中,可以求得Δ2+1作为上界,即次大度加1。通过观察是原图是否存在Kn的子图,若存在,则下界为n。例如,若原图存在K3即三角形,则点色数至少为3。

(2) 求边色数

① G是简单图,则χ’=Δ或Δ+1

② G是偶图,则χ’=Δ

③ G是简单图,若n=2k+1且m>kΔ,则χ’=Δ+1

④ G是奇阶Δ正则简单图,则χ’=Δ+1

⑤ 设无环图G中边的最大重数为μ,则χ’=Δ+μ

(3) 着色算法

对色集标号,每次给顶点着符合条件(相邻的顶点不能着相同颜色)的最小颜色数。该算法只能保证最多用Δ+1种颜色给一个图正常着色,但不能保证使用的颜色数一定是最少。

(4) 着色计数(求色多项式)

缩边、加边递推法

① G为n阶空图,则 Pk(G)=kn

② Pk(Kn)=k(k-1)(k-2)…(k-n+1)

③ 若d(u)=1,则 Pk(G)=(k-1)  Pk(G-u)

④ 加边递推法Pk(G-e) =  Pk(G)+  Pk(G.e)

减边递推法Pk(G)= Pk(G-e)- Pk(G.e)

理想子图法

理想子图法改进
3.9 覆盖模型

(1)点覆盖

一个图的点独立集(简称独立集)是指图中一些互不相邻的点构成的点子集。含点数最多的独立集称最大独立集,最大独立集所含的顶点数称为G的独立数,记为α(G),简记为α

G的一个覆盖是指G的一个顶点子集K,使得G的每条边都至少有一个端点属于K。G的最小覆盖的点数称G的覆盖数,记为β(G),简记为β

(2) 边覆盖

G的最大匹配的边数称为G的边独立数,记为α’(G),简记为α’。

设L是G的一个边子集

G的一个边覆盖是指G的一个边子集L,使得G的每个点均为L中某条边的端点。G的最小覆盖的边数称G的边覆盖数,记为β’(G),简记为β’

(3) 点覆盖与边覆盖关系

① 对任意n阶图G,均有α+β=n

② 对任意n阶图G,且δ(G)>0均有α’+β’=n

③ G是δ(G)>0的偶图,则α=β’

3.10 强连通定向算法
(1) 存在性问题
    定理3( 罗宾斯,1939) 非平凡连通图G具有强连通定向 <==> G是2边连通的。
(2) 强连通定向算法
    从已标号集合L中选择其与未标号集合U有邻点的最高标号的点v,扩展该点u,并标点u为点v标号值加1。对所有未赋方向的边,由标号值大的顶点指向标号值小的顶点

3.11 点边面关系运算

① 握手定理:图G= (V, E)中所有顶点的度的和等于边数m的2倍

② 设T是(n, m)树,则:n=m-1

③ 设G=(n,m)是平面图,则∑deg(f) = 2m

④ 平面图欧拉公式:设G=(n,m)是连通平面图,φ是G的面数,则n-m+φ=2

 

四、图论分支

4.1 网络图论

网络图论又称为网络拓扑学,用图的理论,对电路的结构及其连接性质进行分析和研究。

4.2 极值图论

主要研究与图相关的极大极小问题。比如最短路径、最小生成树、最大匹配、最小覆盖、最大流等问题。更多信息,请参考维基百科Extremal Graph Theory

4.3 代数图论

用代数方法研究图论问题。更多信息,请参考维基百科Algebraic Graph Theory

4.4 拓扑图论

直接看英文吧,It studies the embedding of graphs in surfaces, spatial embeddings of graphs, and graphs as topological spaces.It also studies immersions of graphs.更多信息,请参考维基百科Topological Graph Theory

4.5 随机图论

研究以某种随机方式产生点数、边数以及边的图(英文原文:A random graph is a graph in which properties such as the number of graph vertices, graph edges, and connections between them are determined in some random way.)。更多信息,请参考维基百科Random Graph

4.6 结构图论

结构图论的核心是哈密顿问题[3]。

 

五、几组易混概念

5.1 图论与拓扑学

图论以前是作为拓扑学一章来讲解,现在已经发展为独立的学科。百度百科词条拓扑学,说拓扑学是近代发展起来的一个研究连续性现象的数学分支。很费解对吧,看新浪爱问知识人一回答,说“拓扑学”主要研究的是出于数学分析的需要而产生的一些几何问题。发展至今,拓扑学主要研究拓扑空间在拓扑变换下的不变性质和不变量。 维基百科词条图论,说图论的研究对象相当于一维的拓扑学。

5.2 途径、迹、路

5.3 欧拉闭迹 欧拉环游 欧拉回路

5.4 H路 H圈 H图

 

注:这几个,等再看一遍书后再总结。

 

六、进一步阅读

老师PPT给出如下参考文献,我们用的是研究生教材(张先迪,李正良.图论及其应用[M].北京:高等教育出版社.2005.2),感觉该教材主要是抄[1]的,难怪不是著而是主编。我看过[2]的,比较浅显易懂,而且给出很多人物背景介绍,读起来比较有意思。[3]我们老师也推荐比较多。

[1]美,帮迪《图论及其应用》

[2]美,Gary Chartrand《图论导引》,人民邮电出版社,2007

[3]Bela Bollobas,《现代图论》,科学出版社,2001 中国科学院研究生教学丛书

[4]美,Fred Buckley《图论简明教程》,清华大学出版社,2005  李慧霸 王风芹译

[5] 李尉萱,《图论》,湖南科学技术出版社,1979

[6] 美,Douglas B.West《图论导引》,机械工业出版社,2007 李建中,骆吉洲译

[7] 杨洪,《图论常用算法选编》,中国铁道出版社,1988

[8] 陈树柏,《网络图论及其应用》,科学出版社,1982

[9] Chris Godsil,Gordon Royle 《Algebraic Graph Theory》,世界图书出版公司北京公司,2004

[10] 王朝瑞,《图论》,高等教育出版社,1983

 

参考文献

[1]张先迪,李正良.图论及其应用[M].北京:高等教育出版社.2005.2

[2]Gary Chartrand,Ping Zhang著.范益政,汪毅译.图论导引[M].北京:人民邮电出版社.2007.9

[3]陈德钦,曾克扬,赵克文.海南在结构图论、组合矩阵论和极值集合论的世界核心领域的贡献[J].科技信息(科学教研).2008年07期

 

Category: OI | Tags: 图论
4
2
2013
3

Lucas定理——求组合数取模

考虑n! mod p

n! mod p

 = (1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * ... n) mod p

 = (1 * 2 * 3 * ... * p * p+1 * p+2 * ... * 2p * 2p+1 * 2p+2 * 2p+3 * ...) mod p

 = (1 * 2 * 3 * ... * p-1 * p+1 * p+2 * ... * 2p-1 * 2p+1 * ... *p^(n/p-1)* (2*3*...*n/p) ) mod p

其中

1 * 2 * 3 * ... p-1 mod p = p+1 * p+2 * p+3 * p+4 ... * 2p-1 mod p = ... = (n%p!) mod p

相当于每p段加上p,所以全部约掉,就是n%p! mod p。

所以,只需要计算C(n%p,m%p) * Lucas(n/p,m/p)

简化: 

C(N,M) mod p=C(Np0,Mp0)*C(Np1,Mp1) * C(Npx,Mpx)

NpX,MpX表示N和M在p进制下的第 X 位。

----------------------------------------------------------------------------------------------------------------------------------------

扩展,求C(N,M) MOD P^c

……前面变成p^c周期……然后单独处理周期。。
Category: OI | Tags: 数学
2
7
2013
2

后缀自动机……

看一次忘一次,蛋疼死了。

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>
const int char_size=26;
const int pool_size=100000;
class suffixs_automaton
{
public:
	struct suffix_node{
		bool start;
		int length;
		suffix_node * clean(){
			return this;
		}
		suffix_node*ch[char_size];
		suffix_node*f;
		suffix_node(){
			start=false;
			length=0;
			f=NULL;memset(ch,0,sizeof(ch));
		};
	};
private:
	// 私有变量
	suffix_node suffix_node_pool[pool_size+1];
	int poolsize;
	suffix_node*alloca_node(){ if (poolsize==pool_size) {suffix_node *sn = new suffix_node();assert(sn);}return suffix_node_pool[poolsize++].clean();};
	suffix_node*tail;
	suffix_node*start;
	int length;
public:
	suffixs_automaton(int *c,int len); // [0,len)
	const suffix_node * get_start();
	void add(int c);
private:
	// 内部函数
};
suffixs_automaton::suffixs_automaton(int *c,int len){
	poolsize = 0;
	start = tail = alloca_node();
	start->start=true;length=0;
	for (int i=0;i<len;i++) add(c[i]);
};
const suffixs_automaton::suffix_node * suffixs_automaton::get_start(){
	return start;
};
void suffixs_automaton::add(int c){
	length++;suffix_node*p=tail;suffix_node*np=alloca_node();
	np->length = tail->length+1;
	for (;!!p && !p->ch[c];p=p->f) p->ch[c]=np;
	tail = np;
	if (!p) {np->f=start;return ;}
	if (p->ch[c]->length==p->length+1) np->f=p->ch[c];
	else
	{
		suffix_node*r = alloca_node();suffix_node *q=p->ch[c];
		*r=*q;
		r->length = p->length+1;
		q->f=np->f=r;
		for (;p&&p->ch[c]==q;p=p->f) p->ch[c]=r;
	}
};
int p[]={0,2,0,3,3};
suffixs_automaton SA(p,5);
char c[255];
void dfs(const suffixs_automaton::suffix_node *sn,int l){
	assert(sn);
	if (l!=0) printf("%s\n",c);
	for (int i=0;i<5;i++)
		if (sn->ch[i]){
			c[l]='A'+i;
			dfs(sn->ch[i],l+1);
			c[l]=0;
		}
}
int main(){
	const suffixs_automaton::suffix_node *sn = SA.get_start();
	dfs(sn,0);
	system("pause");
};
Category: OI | Tags: 字符串处理

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com