目录
一.数论... 4
1.阶乘最后非零位... 4
2. 模线性方程(组) 4
3. 素数表... 6
4. 素数随机判定(miller_rabin) 6
5. 质因数分解... 7
6. 最大公约数欧拉函数... 8
二.图论_匹配... 9
1. 二分图最大匹配(hungary邻接表形式) 9
2. 二分图最大匹配(hungary邻接表形式,邻接阵接口) 10
3. 二分图最大匹配(hungary邻接阵形式) 10
4. 二分图最大匹配(hungary正向表形式) 11
5. 二分图最佳匹配(kuhn_munkras邻接阵形式) 11
6. 一般图匹配(邻接表形式) 12
7. 一般图匹配(邻接表形式,邻接阵接口) 13
8. 一般图匹配(邻接阵形式) 14
9. 一般图匹配(正向表形式) 15
三.图论_生成树... 16
1. 最小生成树(kruskal邻接表形式) 16
2. 最小生成树(kruskal正向表形式) 17
3. 最小生成树(prim+binary_heap邻接表形式) 19
4. 最小生成树(prim+binary_heap正向表形式) 20
5. 最小生成树(prim+mapped_heap邻接表形式) 21
6. 最小生成树(prim+mapped_heap正向表形式) 22
7. 最小生成树(prim邻接阵形式) 23
8. 最小树形图(邻接阵形式) 24
四.图论_网络流... 25
1. 上下界最大流(邻接表形式) 25
2. 上下界最大流(邻接阵形式) 26
3. 上下界最小流(邻接表形式) 27
4. 上下界最小流(邻接阵形式) 29
5. 最大流(邻接表形式) 30
6. 最大流(邻接表形式,邻接阵接口) 31
7. 最大流(邻接阵形式) 32
8. 最大流无流量(邻接阵形式) 32
9. 最小费用最大流(邻接阵形式) 33
五. 图论_最短路径... 34
1. 最短路径(单源bellman_ford邻接阵形式) 34
2. 最短路径(单源dijkstra_bfs邻接表形式) 35
3. 最短路径(单源dijkstra_bfs正向表形式) 35
4. 最短路径(单源dijkstra+binary_heap邻接表形式) 36
5. 最短路径(单源dijkstra+binary_heap正向表形式) 37
6. 最短路径(单源dijkstra+mapped_heap邻接表形式) 38
7. 最短路径(单源dijkstra+mapped_heap正向表形式) 39
8. 最短路径(单源dijkstra邻接阵形式) 40
9. 最短路径(多源floyd_warshall邻接阵形式) 40
六. 图论_连通性... 41
1. 无向图关键边(dfs邻接阵形式) 41
2. 无向图关键点(dfs邻接阵形式) 42
3. 无向图块(bfs邻接阵形式) 43
4. 无向图连通分支(bfs邻接阵形式) 43
5. 无向图连通分支(dfs邻接阵形式) 44
6. 有向图强连通分支(bfs邻接阵形式) 44
7. 有向图强连通分支(dfs邻接阵形式) 45
8. 有向图最小点基(邻接阵形式) 46
七. 图论_应用... 46
1.欧拉回路(邻接阵形式) 46
2. 前序表转化... 47
3. 树的优化算法... 48
4. 拓扑排序(邻接阵形式). 49
5. 最佳边割集... 50
6. 最佳顶点割集... 51
7. 最小边割集... 52
8. 最小顶点割集... 53
9. 最小路径覆盖... 55
八. 图论_NP搜索... 55
1. 最大团(n小于64)(faster) 55
2. 最大团... 58
九. 组合... 59
1. 排列组合生成... 59
2. 生成gray码... 60
3. 置换(polya) 61
4. 字典序全排列... 61
5. 字典序组合... 62
6. 组合公式... 62
十. 数值计算... 63
1. 定积分计算(Romberg) 63
2. 多项式求根(牛顿法) 64
3. 周期性方程(追赶法) 66
十一. 几何... 67
1. 多边形... 67
2. 多边形切割... 70
3. 浮点函数... 71
4. 几何公式... 76
5. 面积... 78
6. 球面... 79
7. 三角形... 79
8. 三维几何... 81
9. 凸包(graham) 89
10. 网格(pick) 91
11. 圆... 92
12. 整数函数... 94
13. 注意... 96
十二. 结构... 97
1. 并查集... 97
2. 并查集扩展(friend_enemy) 98
3. 堆(binary) 98
4. 堆(mapped) 99
5. 矩形切割... 99
6. 线段树... 100
7. 线段树扩展... 102
8. 线段树应用... 105
9. 子段和... 105
10. 子阵和... 105
十三. 其他... 106
1. 分数... 106
2. 矩阵... 108
3. 日期... 110
4. 线性方程组(gauss) 111
5. 线性相关... 113
十四. 应用... 114
1. joseph. 114
2. N皇后构造解... 115
3. 布尔母函数... 115
4. 第k元素... 116
5. 幻方构造... 116
6. 模式匹配(kmp) 118
7. 逆序对数... 118
8. 字符串最小表示... 119
9. 最长公共单调子序列... 119
10. 最长子序列... 120
11. 最大子串匹配... 121
12. 最大子段和... 122
13. 最大子阵和... 123
1.阶乘最后非零位
//求阶乘最后非零位,复杂度O(nlogn)
//返回该位,n以字符串方式传入
#include
#define MAXN 10000
int lastdigit(char* buf){
const int mod[20]={1,1,2,6,4,2,2,4,2,8,4,4,8,4,6,8,8,6,8,2};
int len=strlen(buf),a[MAXN],i,c,ret=1;
if (len==1)
return mod[buf[0]-'0'];
for (i=0;i
a[i]=buf[len-1-i]-'0';
for (;len;len-=!a[len-1]){
ret=ret*mod[a[1]%2*10+a[0]]%5;
for (c=0,i=len-1;i>=0;i--)
c=c*10+a[i],a[i]=c/5,c%=5;
}
return ret+ret%2*5;
}
2. 模线性方程(组)
#ifdef WIN32
typedef __int64 i64;
#else
typedef long long i64;
#endif
//扩展Euclid求解gcd(a,b)=ax+by
int ext_gcd(int a,int b,int& x,int& y){
int t,ret;
if (!b){
x=1,y=0;
return a;
}
ret=ext_gcd(b,a%b,x,y);
t=x,x=y,y=t-a/b*y;
return ret;
}
//计算m^a, O(loga), 本身没什么用, 注意这个按位处理的方法 :-P
int exponent(int m,int a){
int ret=1;
for (;a;a>>=1,m*=m)
if (a&1)
ret*=m;
return ret;
}
//计算幂取模a^b mod n, O(logb)
int modular_exponent(int a,int b,int n){ //a^b mod n
int ret=1;
for (;b;b>>=1,a=(int)((i64)a)*a%n)
if (b&1)
ret=(int)((i64)ret)*a%n;
return ret;
}
//求解模线性方程ax=b (mod n)
//返回解的个数,解保存在sol[]中
//要求n>0,解的范围0..n-1
int modular_linear(int a,int b,int n,int* sol){
int d,e,x,y,i;
d=ext_gcd(a,n,x,y);
if (b%d)
return 0;
e=(x*(b/d)%n+n)%n;
for (i=0;i
sol[i]=(e+i*(n/d))%n;
return d;
}
//求解模线性方程组(中国余数定理)
// x = b[0] (mod w[0])
// x = b[1] (mod w[1])
// ...
// x = b[k-1] (mod w[k-1])
//要求w[i]>0,w[i]与w[j]互质,解的范围1..n,n=w[0]*w[1]*...*w[k-1]
int modular_linear_system(int b[],int w[],int k){
int d,x,y,a=0,m,n=1,i;
for (i=0;i
n*=w[i];
for (i=0;i
m=n/w[i];
d=ext_gcd(w[i],m,x,y);
a=(a+y*m*b[i])%n;
}
return (a+n)%n;
}
3. 素数表
//用素数表判定素数,先调用initprime
int plist[10000],pcount=0;
int prime(int n){
int i;
if ((n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&!(n%7)))
return 0;
for (i=0;plist[i]*plist[i]<=n;i++)
if (!(n%plist[i]))
return 0;
return n>1;
}
void initprime(){
int i;
for (plist[pcount++]=2,i=3;i<50000;i++)
if (prime(i))
plist[pcount++]=i;
}
4. 素数随机判定(miller_rabin)
//miller rabin
//判断自然数n是否为素数
//time越高失败概率越低,一般取10到50
#include
#ifdef WIN32
typedef __int64 i64;
#else
typedef long long i64;
#endif
int modular_exponent(int a,int b,int n){ //a^b mod n
int ret;
for (;b;b>>=1,a=(int)((i64)a)*a%n)
if (b&1)
ret=(int)((i64)ret)*a%n;
return ret;
}
// Carmicheal number: 561,41041,825265,321197185
int miller_rabin(int n,int time=10){
if (n==1||(n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&!(n%7)))
return 0;
while (time--)
if (modular_exponent(((rand()&0x7fff<<16)+rand()&0x7fff+rand()&0x7fff)%(n-1)+1,n-1,n)!=1)
return 0;
return 1;
}
5. 质因数分解
//分解质因数
//prime_factor()传入n, 返回不同质因数的个数
//f存放质因数,nf存放对应质因数的个数
//先调用initprime(),其中第二个initprime()更快
#include
#include
#include
using namespace std;
#define MAXN 2001000
#define PSIZE 100000
int plist[PSIZE], pcount=0;
int prime(int n){
int i;
if ((n!=2&&!(n%2))||(n!=3&&!(n%3))||(n!=5&&!(n%5))||(n!=7&&!(n%7)))
return 0;
for (i=0;plist[i]*plist[i]<=n;++i)
if (!(n%plist[i]))
return 0;
return n>1;
}
void initprime(){
int i;
for (plist[pcount++]=2,i=3;i<100000;++i)
if (prime(i))
plist[pcount++]=i;
}
int prime_factor(int n, int* f, int *nf) {
int cnt = 0;
int n2 = sqrt((double)n);
for(int i = 0; n > 1 && plist[i] <= n2; ++i)
if (n % plist[i] == 0) {
for (nf[cnt] = 0; n % plist[i] == 0; ++nf[cnt], n /= plist[i]);
f[cnt++] = plist[i];
}
if (n > 1) nf[cnt] = 1, f[cnt++] = n;
return cnt;
}
/*
//产生MAXN以内的所有素数
//note:2863311530就是10101010101010101010101010101010
//给所有2的倍数赋初值
#include
#include
using namespace std;
#define MAXN 100000000
unsigned int plist[6000000],pcount;
unsigned int isprime[(MAXN>>5)+1];
#define setbitzero(a) (isprime[(a)>>5]&=(~(1<<((a)&31))))
#define setbitone(a) (isprime[(a)>>5]|=(1<<((a)&31)))
#define ISPRIME(a) (isprime[(a)>>5]&(1<<((a)&31)))
void initprime(){
int i,j,m;
int t=(MAXN>>5)+1;
for(i=0;i
plist[0]=2;setbitone(2);setbitzero(1);
m=(int)sqrt(MAXN);
for(pcount=1,i=3;i<=m;i+=2)
if(ISPRIME(i))
for(plist[pcount++]=i,j=i<<1;j<=MAXN;j+=i)
setbitzero(j);
if(!(i&1))++i;
for(;i<=MAXN;i+=2)if(ISPRIME(i))plist[pcount++]=i;
}
6. 最大公约数欧拉函数
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
inline int lcm(int a,int b){
return a/gcd(a,b)*b;
}
//求1..n-1中与n互质的数的个数
int eular(int n){
int ret=1,i;
for (i=2;i*i<=n;i++)
if (n%i==0){
n/=i,ret*=i-1;
while (n%i==0)
n/=i,ret*=i;
}
if (n>1)
ret*=n-1;
return ret;
}
1. 二分图最大匹配(hungary邻接表形式)
//二分图最大匹配,hungary算法,邻接表形式,复杂度O(m*e)
//返回最大匹配数,传入二分图大小m,n和邻接表list(只需一边)
//match1,match2返回一个最大匹配,未匹配顶点match值为-1
#include
#define MAXN 310
#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)
struct edge_t{
int from,to;
edge_t* next;
};
int hungary (int m,int n,edge_t* list[],int* match1,int* match2){
int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;edge_t* e;
for (_clr(match1),_clr(match2),i=0;i
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for (e=list[k=s[p]];e&&match1[i]<0;e=e->next)
if (t[j=e->to]<0){
s[++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
return ret;
}
2. 二分图最大匹配(hungary邻接表形式,邻接阵接口)
//二分图最大匹配,hungary算法,邻接表形式,邻接阵接口,复杂度O(m*e)s
//返回最大匹配数,传入二分图大小m,n和邻接阵
//match1,match2返回一个最大匹配,未匹配顶点match值为-1
#include
#include
#define MAXN 310
#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)
int hungary(int m,int n,int mat[][MAXN],int* match1,int* match2){
int s[MAXN],t[MAXN],p,q,ret=0,i,j,k,r;
vector
//生成邻接表(只需一边)
for(i=0;i
for(j=0;j
if (mat[i][j]) e[i].push_back(j);
for (_clr(match1),_clr(match2),i=0;i
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for(r=0,k=s[p];r
if (t[j=e[k][r]]<0){
s[++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
return ret;
}
3. 二分图最大匹配(hungary邻接阵形式)
//二分图最大匹配,hungary算法,邻接阵形式,复杂度O(m*m*n)
//返回最大匹配数,传入二分图大小m,n和邻接阵mat,非零元素表示有边
//match1,match2返回一个最大匹配,未匹配顶点match值为-1
#include
#define MAXN 310
#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)
int hungary(int m,int n,int mat[][MAXN],int* match1,int* match2){
int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;
for (_clr(match1),_clr(match2),i=0;i
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for (k=s[p],j=0;j
if (mat[k][j]&&t[j]<0){
s[++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
return ret;
}
4. 二分图最大匹配(hungary正向表形式)
//二分图最大匹配,hungary算法,正向表形式,复杂度O(m*e)
//返回最大匹配数,传入二分图大小m,n和正向表list,buf(只需一边)
//match1,match2返回一个最大匹配,未匹配顶点match值为-1
#include
#define MAXN 310
#define _clr(x) memset(x,0xff,sizeof(int)*MAXN)
int hungary (int m,int n,int* list,int* buf,int* match1,int* match2){
int s[MAXN],t[MAXN],p,q,ret=0,i,j,k,l;
for (_clr(match1),_clr(match2),i=0;i
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for (l=list[k=s[p]];l
if (t[j=buf[l]]<0){
s[++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
return ret;
}
5. 二分图最佳匹配(kuhn_munkras邻接阵形式)
//二分图最佳匹配,kuhn munkras算法,邻接阵形式,复杂度O(m*m*n)
//返回最佳匹配值,传入二分图大小m,n和邻接阵mat,表示权值
//match1,match2返回一个最佳匹配,未匹配顶点match值为-1
//一定注意m<=n,否则循环无法终止
//最小权匹配可将权值取相反数
#include
#define MAXN 310
#define inf 1000000000
#define _clr(x) memset(x,0xff,sizeof(int)*n)
int kuhn_munkras(int m,int n,int mat[][MAXN],int* match1,int* match2){
int s[MAXN],t[MAXN],l1[MAXN],l2[MAXN],p,q,ret=0,i,j,k;
for (i=0;i
for (l1[i]=-inf,j=0;j
l1[i]=mat[i][j]>l1[i]?mat[i][j]:l1[i];
for (i=0;i
for (_clr(match1),_clr(match2),i=0;i
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for (k=s[p],j=0;j
if (l1[k]+l2[j]==mat[k][j]&&t[j]<0){
s[++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
if (match1[i]<0){
for (i--,p=inf,k=0;k<=q;k++)
for (j=0;j
if (t[j]<0&&l1[s[k]]+l2[j]-mat[s[k]][j]
p=l1[s[k]]+l2[j]-mat[s[k]][j];
for (j=0;j
for (k=0;k<=q;l1[s[k++]]-=p);
}
}
for (i=0;i
ret+=mat[i][match1[i]];
return ret;
}
6. 一般图匹配(邻接表形式)
//一般图最大匹配,邻接表形式,复杂度O(n*e)
//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1
//传入图的顶点数n和邻接表list
#define MAXN 100
struct edge_t{
int from,to;
edge_t* next;
};
int aug(int n,edge_t* list[],int* match,int* v,int now){
int t,ret=0;edge_t* e;
v[now]=1;
for (e=list[now];e;e=e->next)
if (!v[t=e->to]){
if (match[t]<0)
match[now]=t,match[t]=now,ret=1;
else{
v[t]=1;
if (aug(n,list,match,v,match[t]))
match[now]=t,match[t]=now,ret=1;
v[t]=0;
}
if (ret)
break;
}
v[now]=0;
return ret;
}
int graph_match(int n,edge_t* list[],int* match){
int v[MAXN],i,j;
for (i=0;i
v[i]=0,match[i]=-1;
for (i=0,j=n;i
if (match[i]<0&&aug(n,list,match,v,i))
i=0,j-=2;
else
i++;
for (i=j=0;i
j+=(match[i]>=0);
return j/2;
}
7. 一般图匹配(邻接表形式,邻接阵接口)
//一般图最大匹配,邻接表形式,复杂度O(n*e)
//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1
//传入图的顶点数n和邻接表list
#include
#define MAXN 100
int aug(int n,vector
int t,ret=0,r;
v[now]=1;
// for (e=list[now];e;e=e->next)
for (r=0;r
if (!v[t=list[now][r]]){
if (match[t]<0)
match[now]=t,match[t]=now,ret=1;
else{
v[t]=1;
if (aug(n,list,match,v,match[t]))
match[now]=t,match[t]=now,ret=1;
v[t]=0;
}
if (ret)
break;
}
v[now]=0;
return ret;
}
int graph_match(int n,int mat[][MAXN],int* match){
int v[MAXN],i,j;
vector
for (i=0;i
for (j=0;j
if (mat[i][j]) list[i].push_back(j);
for (i=0;i
v[i]=0,match[i]=-1;
for (i=0,j=n;i
if (match[i]<0&&aug(n,list,match,v,i))
i=0,j-=2;
else
i++;
for (i=j=0;i
j+=(match[i]>=0);
return j/2;
}
8. 一般图匹配(邻接阵形式)
//一般图最大匹配,邻接阵形式,复杂度O(n^3)
//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1
//传入图的顶点数n和邻接阵mat
#define MAXN 100
int aug(int n,int mat[][MAXN],int* match,int* v,int now){
int i,ret=0;
v[now]=1;
for (i=0;i
if (!v[i]&&mat[now][i]){
if (match[i]<0)
match[now]=i,match[i]=now,ret=1;
else{
v[i]=1;
if (aug(n,mat,match,v,match[i]))
match[now]=i,match[i]=now,ret=1;
v[i]=0;
}
if (ret)
break;
}
v[now]=0;
return ret;
}
int graph_match(int n,int mat[][MAXN],int* match){
int v[MAXN],i,j;
for (i=0;i
v[i]=0,match[i]=-1;
for (i=0,j=n;i
if (match[i]<0&&aug(n,mat,match,v,i))
i=0,j-=2;
else
i++;
for (i=j=0;i
j+=(match[i]>=0);
return j/2;
}
9. 一般图匹配(正向表形式)
//一般图最大匹配,正向表形式,复杂度O(n*e)
//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1
//传入图的顶点数n和正向表list,buf
#define MAXN 100
int aug(int n,int* list,int* buf,int* match,int* v,int now){
int i,t,ret=0;
v[now]=1;
for (i=list[now];i
if (!v[t=buf[i]]){
if (match[t]<0)
match[now]=t,match[t]=now,ret=1;
else{
v[t]=1;
if (aug(n,list,buf,match,v,match[t]))
match[now]=t,match[t]=now,ret=1;
v[t]=0;
}
if (ret)
break;
}
v[now]=0;
return ret;
}
int graph_match(int n,int* list,int* buf,int* match){
int v[MAXN],i,j;
for (i=0;i
v[i]=0,match[i]=-1;
for (i=0,j=n;i
if (match[i]<0&&aug(n,list,buf,match,v,i))
i=0,j-=2;
else
i++;
for (i=j=0;i
j+=(match[i]>=0);
return j/2;
}
1. 最小生成树(kruskal邻接表形式)
//无向图最小生成树,kruskal算法,邻接表形式,复杂度O(mlogm)
//返回最小生成树的长度,传入图的大小n和邻接表list
//可更改边权的类型,edge[][2]返回树的构造,用边集表示
//如果图不连通,则对各连通分支构造最小生成树,返回总长度
#include
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
struct edge_t{
int from,to;
elem_t len;
edge_t* next;
};
#define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))
#define _run_both _ufind_run(i);_ufind_run(j)
struct ufind{
int p[MAXN],t;
void init(){memset(p,0,sizeof(p));}
void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}
int is_friend(int i,int j){_run_both;return i==j&&i;}
};
#define _cp(a,b) ((a).len<(b).len)
struct heap_t{int a,b;elem_t len;};
struct minheap{
heap_t h[MAXN*MAXN];
int n,p,c;
void init(){n=0;}
void ins(heap_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
h[p]=e;
}
int del (heap_t& e){
if (!n) return 0;
for (e=h[p=1],c=2;c
h[p]=h[n--];return 1;
}
};
elem_t kruskal(int n,edge_t* list[],int edge[][2]){
ufind u;minheap h;
edge_t* t;heap_t e;
elem_t ret=0;int i,m=0;
u.init(),h.init();
for (i=0;i
for (t=list[i];t;t=t->next)
if (i
e.a=i,e.b=t->to,e.len=t->len,h.ins(e);
while (m
if (!u.is_friend(e.a+1,e.b+1))
edge[m][0]=e.a,edge[m][1]=e.b,ret+=e.len,u.set_friend(e.a+1,e.b+1);
return ret;
}
2. 最小生成树(kruskal正向表形式)
//无向图最小生成树,kruskal算法,正向表形式,复杂度O(mlogm)
//返回最小生成树的长度,传入图的大小n和正向表list,buf
//可更改边权的类型,edge[][2]返回树的构造,用边集表示
//如果图不连通,则对各连通分支构造最小生成树,返回总长度
#include
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
struct edge_t{
int to;
elem_t len;
};
#define _ufind_run(x) for(;p[t=x];x=p[x],p[t]=(p[x]?p[x]:x))
#define _run_both _ufind_run(i);_ufind_run(j)
struct ufind{
int p[MAXN],t;
void init(){memset(p,0,sizeof(p));}
void set_friend(int i,int j){_run_both;p[i]=(i==j?0:j);}
int is_friend(int i,int j){_run_both;return i==j&&i;}
};
#define _cp(a,b) ((a).len<(b).len)
struct heap_t{int a,b;elem_t len;};
struct minheap{
heap_t h[MAXN*MAXN];
int n,p,c;
void init(){n=0;}
void ins(heap_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
h[p]=e;
}
int del (heap_t& e){
if (!n) return 0;
for (e=h[p=1],c=2;c
h[p]=h[n--];return 1;
}
};
elem_t kruskal(int n,int* list,edge_t* buf,int edge[][2]){
ufind u;minheap h;
heap_t e;elem_t ret=0;
int i,j,m=0;
u.init(),h.init();
for (i=0;i
for (j=list[i];j
if (i
e.a=i,e.b=buf[j].to,e.len=buf[j].len,h.ins(e);
while (m
if (!u.is_friend(e.a+1,e.b+1))
edge[m][0]=e.a,edge[m][1]=e.b,ret+=e.len,u.set_friend(e.a+1,e.b+1);
return ret;
}
3. 最小生成树(prim+binary_heap邻接表形式)
//无向图最小生成树,prim算法+二分堆,邻接表形式,复杂度O(mlogm)
//返回最小生成树的长度,传入图的大小n和邻接表list
//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1
//必须保证图的连通的!
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
struct edge_t{
int from,to;
elem_t len;
edge_t* next;
};
#define _cp(a,b) ((a).d<(b).d)
struct heap_t{elem_t d;int v;};
struct heap{
heap_t h[MAXN*MAXN];
int n,p,c;
void init(){n=0;}
void ins(heap_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
h[p]=e;
}
int del (heap_t& e){
if (!n) return 0;
for (e=h[p=1],c=2;c
h[p]=h[n--];return 1;
}
};
elem_t prim(int n,edge_t* list[],int* pre){
heap h;
elem_t min[MAXN],ret=0;
edge_t* t;heap_t e;
int v[MAXN],i;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
h.init();e.v=0,e.d=0,h.ins(e);
while (h.del(e))
if (!v[e.v])
for (v[e.v]=1,ret+=e.d,t=list[e.v];t;t=t->next)
if (!v[t->to]&&t->len
pre[t->to]=t->from,min[e.v=t->to]=e.d=t->len,h.ins(e);
return ret;
}
4. 最小生成树(prim+binary_heap正向表形式)
//无向图最小生成树,prim算法+二分堆,正向表形式,复杂度O(mlogm)
//返回最小生成树的长度,传入图的大小n和正向表list,buf
//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1
//必须保证图的连通的!
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
struct edge_t{
int to;
elem_t len;
};
#define _cp(a,b) ((a).d<(b).d)
struct heap_t{elem_t d;int v;};
struct heap{
heap_t h[MAXN*MAXN];
int n,p,c;
void init(){n=0;}
void ins(heap_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
h[p]=e;
}
int del (heap_t& e){
if (!n) return 0;
for (e=h[p=1],c=2;c
h[p]=h[n--];return 1;
}
};
elem_t prim(int n,int* list,edge_t* buf,int* pre){
heap h;heap_t e;
elem_t min[MAXN],ret=0;
int v[MAXN],i,j;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
h.init();e.v=0,e.d=0,h.ins(e);
while (h.del(e))
if (!v[i=e.v])
for (v[i]=1,ret+=e.d,j=list[i];j
if (!v[buf[j].to]&&buf[j].len
pre[buf[j].to]=i,min[e.v=buf[j].to]=e.d=buf[j].len,h.ins(e);
return ret;
}
5. 最小生成树(prim+mapped_heap邻接表形式)
//无向图最小生成树,prim算法+映射二分堆,邻接表形式,复杂度O(mlogn)
//返回最小生成树的长度,传入图的大小n和邻接表list
//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1
//必须保证图的连通的!
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
struct edge_t{
int from,to;
elem_t len;
edge_t* next;
};
#define _cp(a,b) ((a)<(b))
struct heap{
elem_t h[MAXN+1];
int ind [MAXN+1],map[MAXN+1],n,p,c;
void init(){n=0;}
void ins(int i,elem_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
h[map[ ind [p]=i]=p]=e;
}
int del (int i,elem_t& e){
i=map[i];if (i<1||i>n) return 0;
for (e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
for (c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
int delmin(int& i,elem_t& e){
if (n<1) return 0;i= ind [1];
for (e=h[p=1],c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
};
elem_t prim(int n,edge_t* list[],int* pre){
heap h;
elem_t min[MAXN],ret=0,e;
edge_t* t;
int v[MAXN],i;
for (h.init(),i=0;i
min[i]=(i?inf:0),v[i]=0,pre[i]=-1,h.ins(i,min[i]);
while (h.delmin(i,e))
for (v[i]=1,ret+=e,t=list[i];t;t=t->next)
if (!v[t->to]&&t->len
pre[t->to]=t->from,h.del(t->to,e),h.ins(t->to,min[t->to]=t->len);
return ret;
}
6. 最小生成树(prim+mapped_heap正向表形式)
//无向图最小生成树,prim算法+映射二分堆,正向表形式,复杂度O(mlogn)
//返回最小生成树的长度,传入图的大小n和正向表list,buf
//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1
//必须保证图的连通的!
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
struct edge_t{
int to;
elem_t len;
};
#define _cp(a,b) ((a)<(b))
struct heap{
elem_t h[MAXN+1];
int ind[MAXN+1],map[MAXN+1],n,p,c;
void init(){n=0;}
void ins(int i,elem_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
h[map[ind[p]=i]=p]=e;
}
int del(int i,elem_t& e){
i=map[i];if (i<1||i>n) return 0;
for (e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
for (c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
int delmin(int& i,elem_t& e){
if (n<1) return 0;i=ind[1];
for (e=h[p=1],c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
};
elem_t prim(int n,int* list,edge_t* buf,int* pre){
heap h;
elem_t min[MAXN],ret=0,e;
int v[MAXN],i,j;
for (h.init(),i=0;i
min[i]=(i?inf:0),v[i]=0,pre[i]=-1,h.ins(i,min[i]);
while (h.delmin(i,e))
for (v[i]=1,ret+=e,j=list[i];j
if (!v[buf[j].to]&&buf[j].len
pre[buf[j].to]=i,h.del(buf[j].to,e),h.ins(buf[j].to,min[buf[j].to]=buf[j].len);
return ret;
}
7. 最小生成树(prim邻接阵形式)
//无向图最小生成树,prim算法,邻接阵形式,复杂度O(n^2)
//返回最小生成树的长度,传入图的大小n和邻接阵mat,不相邻点边权inf
//可更改边权的类型,pre[]返回树的构造,用父结点表示,根节点(第一个)pre值为-1
//必须保证图的连通的!
#define MAXN 200
#define inf 1000000000
typedef double elem_t;
elem_t prim(int n,elem_t mat[][MAXN],int* pre){
elem_t min[MAXN],ret=0;
int v[MAXN],i,j,k;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
for (min[j=0]=0;j
for (k=-1,i=0;i
if (!v[i]&&(k==-1||min[i]
k=i;
for (v[k]=1,ret+=min[k],i=0;i
if (!v[i]&&mat[k][i]
min[i]=mat[pre[i]=k][i];
}
return ret;
}
8. 最小树形图(邻接阵形式)
//多源最小树形图,edmonds算法,邻接阵形式,复杂度O(n^3)
//返回最小生成树的长度,构造失败返回负值
//传入图的大小n和邻接阵mat,不相邻点边权inf
//可更改边权的类型,pre[]返回树的构造,用父结点表示
//传入时pre[]数组清零,用-1标出源点
#include
#define MAXN 120
#define inf 1000000000
typedef int elem_t;
elem_t edmonds(int n,elem_t mat[][MAXN*2],int* pre){
elem_t ret=0;
int c[MAXN*2][MAXN*2],l[MAXN*2],p[MAXN*2],m=n,t,i,j,k;
for (i=0;i
do{
memset(c,0,sizeof(c)),memset(p,0xff,sizeof(p));
for (t=m,i=0;i
for (i=0;i
if (l[i]==i&&pre[i]!=-1){
for (j=0;j
if (l[j]==j&&i!=j&&mat[j][i]
p[i]=j;
if ((pre[i]=p[i])==-1)
return -1;
if (c[i][p[i]]){
for (j=0;j<=m;mat[j][m]=mat[m][j]=inf,j++);
for (k=i;l[k]!=m;l[k]=m,k=p[k])
for (j=0;j
if (l[j]==j){
if (mat[j][k]-mat[p[k]][k]
mat[j][m]=mat[j][k]-mat[p[k]][k];
if (mat[k][j]
mat[m][j]=mat[k][j];
}
c[m][m]=1,l[m]=m,m++;
}
for (j=0;j
if (c[i][j])
for (k=p[i];k!=-1&&l[k]==k;c[k][j]=1,k=p[k]);
}
}
while (t
for (;m-->n;pre[k]=pre[m])
for (i=0;i
if (l[i]==m){
for (j=0;j
if (pre[j]==m&&mat[i][j]==mat[m][j])
pre[j]=i;
if (mat[pre[m]][m]==mat[pre[m]][i]-mat[pre[i]][i])
k=i;
}
for (i=0;i
if (pre[i]!=-1)
ret+=mat[pre[i]][i];
return ret;
}
1. 上下界最大流(邻接表形式)
//求上下界网络最大流,邻接表形式
//返回最大流量,-1表示无可行流,flow返回每条边的流量
//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink
//MAXN应比最大结点数多2,无可行流返回-1时mat未复原!
#define MAXN 100
#define inf 1000000000
int _max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;
vector
for (i=0;i
for (e[i].clear(),j=0;j
if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (r=0;r
i=e[t][r];
if (!pre[i]&&(j=mat[t][i]-flow[t][i]))
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&(j=flow[i][t]))
pre[que[q++]=i]=-t-1,d[i]=d[t]
}
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
for (j=i=0;i
return j;
}
int limit_max_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){
int i,j,sk,ks;
if (source==sink) return inf;
for (mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i
for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j
mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];
sk=mat[source][sink],ks=mat[sink][source],mat[source][sink]=mat[sink][source]=inf;
for (i=0;i
for (j=0;j
_max_flow(n+2,mat,n,n+1,flow);
for (i=0;i
if (flow[n][i]
flow[source][sink]=flow[sink][source]=0,mat[source][sink]=sk,mat[sink][source]=ks;
_max_flow(n,mat,source,sink,flow);
for (i=0;i
for (j=0;j
mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];
for (j=i=0;i
return j;
}
2. 上下界最大流(邻接阵形式)
//求上下界网络最大流,邻接阵形式
//返回最大流量,-1表示无可行流,flow返回每条边的流量
//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink
//MAXN应比最大结点数多2,无可行流返回-1时mat未复原!
#define MAXN 100
#define inf 1000000000
void _max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j;
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (i=0;i
if (!pre[i]&&j=mat[t][i]-flow[t][i])
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&j=flow[i][t])
pre[que[q++]=i]=-t-1,d[i]=d[t]
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
}
int limit_max_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){
int i,j,sk,ks;
if (source==sink) return inf;
for (mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i
for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j
mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];
sk=mat[source][sink],ks=mat[sink][source],mat[source][sink]=mat[sink][source]=inf;
for (i=0;i
for (j=0;j
_max_flow(n+2,mat,n,n+1,flow);
for (i=0;i
if (flow[n][i]
flow[source][sink]=flow[sink][source]=0,mat[source][sink]=sk,mat[sink][source]=ks;
_max_flow(n,mat,source,sink,flow);
for (i=0;i
for (j=0;j
mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];
for (j=i=0;i
return j;
}
3. 上下界最小流(邻接表形式)
//求上下界网络最小流,邻接阵形式
//返回最大流量,-1表示无可行流,flow返回每条边的流量
//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink
//MAXN应比最大结点数多2,无可行流返回-1时mat未复原!
#define MAXN 100
#define inf 1000000000
int _max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;
vector
for (i=0;i
for (e[i].clear(),j=0;j
if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (r=0;r
i=e[t][r];
if (!pre[i]&&(j=mat[t][i]-flow[t][i]))
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&(j=flow[i][t]))
pre[que[q++]=i]=-t-1,d[i]=d[t]
}
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
for (j=i=0;i
return j;
}
int limit_min_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){
int i,j,sk,ks;
if (source==sink) return inf;
for (mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i
for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j
mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];
sk=mat[source][sink],ks=mat[sink][source],mat[source][sink]=mat[sink][source]=inf;
for (i=0;i
for (j=0;j
_max_flow(n+2,mat,n,n+1,flow);
for (i=0;i
if (flow[n][i]
flow[source][sink]=flow[sink][source]=0,mat[source][sink]=sk,mat[sink][source]=ks;
_max_flow(n,mat,sink,source,flow);
for (i=0;i
for (j=0;j
mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];
for (j=i=0;i
return j;
}
4. 上下界最小流(邻接阵形式)
//求上下界网络最小流,邻接阵形式
//返回最大流量,-1表示无可行流,flow返回每条边的流量
//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink
//MAXN应比最大结点数多2,无可行流返回-1时mat未复原!
#define MAXN 100
#define inf 1000000000
void _max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j;
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (i=0;i
if (!pre[i]&&j=mat[t][i]-flow[t][i])
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&j=flow[i][t])
pre[que[q++]=i]=-t-1,d[i]=d[t]
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
}
int limit_min_flow(int n,int mat[][MAXN],int bf[][MAXN],int source,int sink,int flow[][MAXN]){
int i,j,sk,ks;
if (source==sink) return inf;
for (mat[n][n+1]=mat[n+1][n]=mat[n][n]=mat[n+1][n+1]=i=0;i
for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j
mat[i][j]-=bf[i][j],mat[n][i]+=bf[j][i],mat[i][n+1]+=bf[i][j];
sk=mat[source][sink],ks=mat[sink][source],mat[source][sink]=mat[sink][source]=inf;
for (i=0;i
for (j=0;j
_max_flow(n+2,mat,n,n+1,flow);
for (i=0;i
if (flow[n][i]
flow[source][sink]=flow[sink][source]=0,mat[source][sink]=sk,mat[sink][source]=ks;
_max_flow(n,mat,sink,source,flow);
for (i=0;i
for (j=0;j
mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];
for (j=i=0;i
return j;
}
5. 最大流(邻接表形式)
//求网络最大流,邻接表形式
//返回最大流量,flow返回每条边的流量
//传入网络节点数n,容量mat,邻接表list,源点source,汇点sink
//list[i](vector
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],vector
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;
if (source==sink) return inf;
for (i=0;i
for (j=0;j
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (r=0;r
i=list[t][r];
if (!pre[i]&&j=mat[t][i]-flow[t][i])
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&j=flow[i][t])
pre[que[q++]=i]=-t-1,d[i]=d[t]
}
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
for (j=i=0;i
return j;
}
6. 最大流(邻接表形式,邻接阵接口)
//求网络最大流,邻接表形式
//返回最大流量,flow返回每条边的流量
//传入网络节点数n,容量mat,源点source,汇点sink
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;
vector
if (source==sink) return inf;
for (i=0;i
for (j=0;j
//e[i]存放所有以i相邻的点,包括反向边!!!
for (i=0;i
for (e[i].clear(),j=0;j
if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (r=0;r
i=e[t][r];
if (!pre[i]&&(j=mat[t][i]-flow[t][i]))
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&(j=flow[i][t]))
pre[que[q++]=i]=-t-1,d[i]=d[t]
}
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
for (j=i=0;i
return j;
}
7. 最大流(邻接阵形式)
//求网络最大流,邻接阵形式
//返回最大流量,flow返回每条边的流量
//传入网络节点数n,容量mat,源点source,汇点sink
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink,int flow[][MAXN]){
int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j;
if (source==sink) return inf;
for (i=0;i
for (j=0;j
for (;;){
for (i=0;i
pre[t=source]=source+1,d[t]=inf;
for (p=q=0;p<=q&&!pre[sink];t=que[p++])
for (i=0;i
if (!pre[i]&&j=mat[t][i]-flow[t][i])
pre[que[q++]=i]=t+1,d[i]=d[t]
else if (!pre[i]&&j=flow[i][t])
pre[que[q++]=i]=-t-1,d[i]=d[t]
if (!pre[sink]) break;
for (i=sink;i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
for (j=i=0;i
return j;
}
8. 最大流无流量(邻接阵形式)
//求网络最大流,邻接阵形式
//返回最大流量
//传入网络节点数n,容量mat,源点source,汇点sink
//注意mat矩阵被修改
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink){
int v[MAXN],c[MAXN],p[MAXN],ret=0,i,j;
for (;;){
for (i=0;i
v[i]=c[i]=0;
for (c[source]=inf;;){
for (j=-1,i=0;i
if (!v[i]&&c[i]&&(j==-1||c[i]>c[j]))
j=i;
if (j<0) return ret;
if (j==sink) break;
for (v[j]=1,i=0;i
if (mat[j][i]>c[i]&&c[j]>c[i])
c[i]=mat[j][i]
}
for (ret+=j=c[i=sink];i!=source;i=p[i])
mat[p[i]][i]-=j,mat[i][p[i]]+=j;
}
}
9. 最小费用最大流(邻接阵形式)
//求网络最小费用最大流,邻接阵形式
//返回最大流量,flow返回每条边的流量,netcost返回总费用
//传入网络节点数n,容量mat,单位费用cost,源点source,汇点sink
#define MAXN 100
#define inf 1000000000
int min_cost_max_flow(int n,int mat[][MAXN],int cost[][MAXN],int source,int sink,int flow[][MAXN],int& netcost){
int pre[MAXN],min[MAXN],d[MAXN],i,j,t,tag;
if (source==sink) return inf;
for (i=0;i
for (j=0;j
for (netcost=0;;){
for (i=0;i
pre[i]=0,min[i]=inf;
//通过bellman_ford寻找最短路,即最小费用可改进路
for (pre[source]=source+1,min[source]=0,d[source]=inf,tag=1;tag;)
for (tag=t=0;t
if (d[t])
for (i=0;i
if (j=mat[t][i]-flow[t][i]&&min[t]+cost[t][i]
tag=1,min[i]=min[t]+cost[t][i],pre[i]=t+1,d[i]=d[t]
else if (j=flow[i][t]&&min[t]
tag=1,min[i]=min[t]-cost[i][t],pre[i]=-t-1,d[i]=d[t]
if (!pre[sink]) break;
for (netcost+=min[sink]*d[i=sink];i!=source;)
if (pre[i]>0)
flow[pre[i]-1][i]+=d[sink],i=pre[i]-1;
else
flow[i][-pre[i]-1]-=d[sink],i=-pre[i]-1;
}
for (j=i=0;i
return j;
}
1. 最短路径(单源bellman_ford邻接阵形式)
//单源最短路径,bellman_ford算法,邻接阵形式,复杂度O(n^3)
//求出源s到所有点的最短路经,传入图的大小n和邻接阵mat
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,路权可为负,若图包含负环则求解失败,返回0
//优化:先删去负边使用dijkstra求出上界,加速迭代过程
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
int bellman_ford(int n,elem_t mat[][MAXN],int s,elem_t* min,int* pre){
int v[MAXN],i,j,k,tag;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
for (min[s]=0,j=0;j
for (k=-1,i=0;i
if (!v[i]&&(k==-1||min[i]
k=i;
for (v[k]=1,i=0;i
if (!v[i]&&mat[k][i]>=0&&min[k]+mat[k][i]
min[i]=min[k]+mat[pre[i]=k][i];
}
for (tag=1,j=0;tag&&j<=n;j++)
for (tag=i=0;i
for (k=0;k
if (min[k]+mat[k][i]
min[i]=min[k]+mat[pre[i]=k][i],tag=1;
return j<=n;
}
2. 最短路径(单源dijkstra_bfs邻接表形式)
//单源最短路径,用于路权相等的情况,dijkstra优化为bfs,邻接表形式,复杂度O(m)
//求出源s到所有点的最短路经,传入图的大小n和邻接表list,边权值len
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负且相等!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
struct edge_t{
int from,to;
edge_t* next;
};
void dijkstra(int n,edge_t* list[],elem_t len,int s,elem_t* min,int* pre){
edge_t* t;
int i,que[MAXN],f=0,r=0,p=1,l=1;
for (i=0;i
min[i]=inf;
min[que[0]=s]=0,pre[s]=-1;
for (;r<=f;l++,r=f+1,f=p-1)
for (i=r;i<=f;i++)
for (t=list[que[i]];t;t=t->next)
if (min[t->to]==inf)
min[que[p++]=t->to]=len*l,pre[t->to]=que[i];
}
3. 最短路径(单源dijkstra_bfs正向表形式)
//单源最短路径,用于路权相等的情况,dijkstra优化为bfs,正向表形式,复杂度O(m)
//求出源s到所有点的最短路经,传入图的大小n和正向表list,buf,边权值len
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负且相等!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
void dijkstra(int n,int* list,int* buf,elem_t len,int s,elem_t* min,int* pre){
int i,que[MAXN],f=0,r=0,p=1,l=1,t;
for (i=0;i
min[i]=inf;
min[que[0]=s]=0,pre[s]=-1;
for (;r<=f;l++,r=f+1,f=p-1)
for (i=r;i<=f;i++)
for (t=list[que[i]];t
if (min[buf[t]]==inf)
min[que[p++]=buf[t]]=len*l,pre[buf[t]]=que[i];
}
4. 最短路径(单源dijkstra+binary_heap邻接表形式)
//单源最短路径,dijkstra算法+二分堆,邻接表形式,复杂度O(mlogm)
//求出源s到所有点的最短路经,传入图的大小n和邻接表list
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
struct edge_t{
int from,to;
elem_t len;
edge_t* next;
};
#define _cp(a,b) ((a).d<(b).d)
struct heap_t{elem_t d;int v;};
struct heap{
heap_t h[MAXN*MAXN];
int n,p,c;
void init(){n=0;}
void ins(heap_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
h[p]=e;
}
int del(heap_t& e){
if (!n) return 0;
for (e=h[p=1],c=2;c
h[p]=h[n--];return 1;
}
};
void dijkstra(int n,edge_t* list[],int s,elem_t* min,int* pre){
heap h;
edge_t* t;heap_t e;
int v[MAXN],i;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
h.init();min[e.v=s]=e.d=0,h.ins(e);
while (h.del(e))
if (!v[e.v])
for (v[e.v]=1,t=list[e.v];t;t=t->next)
if (!v[t->to]&&min[t->from]+t->len
pre[t->to]=t->from,min[e.v=t->to]=e.d=min[t->from]+t->len,h.ins(e);
}
5. 最短路径(单源dijkstra+binary_heap正向表形式)
//单源最短路径,dijkstra算法+二分堆,正向表形式,复杂度O(mlogm)
//求出源s到所有点的最短路经,传入图的大小n和正向表list,buf
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
struct edge_t{
int to;
elem_t len;
};
#define _cp(a,b) ((a).d<(b).d)
struct heap_t{elem_t d;int v;};
struct heap{
heap_t h[MAXN*MAXN];
int n,p,c;
void init(){n=0;}
void ins(heap_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[p]=h[p>>1],p>>=1);
h[p]=e;
}
int del(heap_t& e){
if (!n) return 0;
for (e=h[p=1],c=2;c
h[p]=h[n--];return 1;
}
};
void dijkstra(int n,int* list,edge_t* buf,int s,elem_t* min,int* pre){
heap h;heap_t e;
int v[MAXN],i,t,f;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
h.init();min[e.v=s]=e.d=0,h.ins(e);
while (h.del(e))
if (!v[e.v])
for (v[f=e.v]=1,t=list[f];t
if (!v[buf[t].to]&&min[f]+buf[t].len
pre[buf[t].to]=f,min[e.v=buf[t].to]=e.d=min[f]+buf[t].len,h.ins(e);
}
6. 最短路径(单源dijkstra+mapped_heap邻接表形式)
//单源最短路径,dijkstra算法+映射二分堆,邻接表形式,复杂度O(mlogn)
//求出源s到所有点的最短路经,传入图的大小n和邻接表list
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
struct edge_t{
int from,to;
elem_t len;
edge_t* next;
};
#define _cp(a,b) ((a)<(b))
struct heap{
elem_t h[MAXN+1];
int ind[MAXN+1],map[MAXN+1],n,p,c;
void init(){n=0;}
void ins(int i,elem_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
h[map[ind[p]=i]=p]=e;
}
int del(int i,elem_t& e){
i=map[i];if (i<1||i>n) return 0;
for (e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
for (c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
int delmin(int& i,elem_t& e){
if (n<1) return 0;i=ind[1];
for (e=h[p=1],c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
};
void dijkstra(int n,edge_t* list[],int s,elem_t* min,int* pre){
heap h;
edge_t* t;elem_t e;
int v[MAXN],i;
for (h.init(),i=0;i
min[i]=((i==s)?0:inf),v[i]=0,pre[i]=-1,h.ins(i,min[i]);
while (h.delmin(i,e))
for (v[i]=1,t=list[i];t;t=t->next)
if (!v[t->to]&&min[i]+t->len
pre[t->to]=i,h.del(t->to,e),min[t->to]=e=min[i]+t->len,h.ins(t->to,e);
}
7. 最短路径(单源dijkstra+mapped_heap正向表形式)
//单源最短路径,dijkstra算法+映射二分堆,正向表形式,复杂度O(mlogn)
//求出源s到所有点的最短路经,传入图的大小n和正向表list,buf
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
struct edge_t{
int to;
elem_t len;
};
#define _cp(a,b) ((a)<(b))
struct heap{
elem_t h[MAXN+1];
int ind[MAXN+1],map[MAXN+1],n,p,c;
void init(){n=0;}
void ins(int i,elem_t e){
for (p=++n;p>1&&_cp(e,h[p>>1]);h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
h[map[ind[p]=i]=p]=e;
}
int del(int i,elem_t& e){
i=map[i];if (i<1||i>n) return 0;
for (e=h[p=i];p>1;h[map[ind[p]=ind[p>>1]]=p]=h[p>>1],p>>=1);
for (c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
int delmin(int& i,elem_t& e){
if (n<1) return 0;i=ind[1];
for (e=h[p=1],c=2;c
h[map[ind[p]=ind[n]]=p]=h[n];n--;return 1;
}
};
void dijkstra(int n,int* list,edge_t* buf,int s,elem_t* min,int* pre){
heap h;elem_t e;
int v[MAXN],i,t;
for (h.init(),i=0;i
min[i]=((i==s)?0:inf),v[i]=0,pre[i]=-1,h.ins(i,min[i]);
while (h.delmin(i,e))
for (v[i]=1,t=list[i];t
if (!v[buf[t].to]&&min[i]+buf[t].len
pre[buf[t].to]=i,h.del(buf[t].to,e),min[buf[t].to]=e=min[i]+buf[t].len,h.ins(buf[t].to,e);
}
8. 最短路径(单源dijkstra邻接阵形式)
//单源最短路径,dijkstra算法,邻接阵形式,复杂度O(n^2)
//求出源s到所有点的最短路经,传入图的顶点数n,(有向)邻接矩阵mat
//返回到各点最短距离min[]和路径pre[],pre[i]记录s到i路径上i的父结点,pre[s]=-1
//可更改路权类型,但必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
void dijkstra(int n,elem_t mat[][MAXN],int s,elem_t* min,int* pre){
int v[MAXN],i,j,k;
for (i=0;i
min[i]=inf,v[i]=0,pre[i]=-1;
for (min[s]=0,j=0;j
for (k=-1,i=0;i
if (!v[i]&&(k==-1||min[i]
k=i;
for (v[k]=1,i=0;i
if (!v[i]&&min[k]+mat[k][i]
min[i]=min[k]+mat[pre[i]=k][i];
}
}
9. 最短路径(多源floyd_warshall邻接阵形式)
//多源最短路径,floyd_warshall算法,复杂度O(n^3)
//求出所有点对之间的最短路经,传入图的大小和邻接阵
//返回各点间最短距离min[]和路径pre[],pre[i][j]记录i到j最短路径上j的父结点
//可更改路权类型,路权必须非负!
#define MAXN 200
#define inf 1000000000
typedef int elem_t;
void floyd_warshall(int n,elem_t mat[][MAXN],elem_t min[][MAXN],int pre[][MAXN]){
int i,j,k;
for (i=0;i
for (j=0;j
min[i][j]=mat[i][j],pre[i][j]=(i==j)?-1:i;
for (k=0;k
for (i=0;i
for (j=0;j
if (min[i][k]+min[k][j]
min[i][j]=min[i][k]+min[k][j],pre[i][j]=pre[k][j];
}
1. 无向图关键边(dfs邻接阵形式)
//无向图的关键边,dfs邻接阵形式,O(n^2)
//返回关键边条数,key[][2]返回边集
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
void search(int n,int mat[][MAXN],int* dfn,int* low,int now,int& cnt,int key[][2]){
int i;
for (low[now]=dfn[now],i=0;i
if (mat[now][i]){
if (!dfn[i]){
dfn[i]=dfn[now]+1;
search(n,mat,dfn,low,i,cnt,key);
if (low[i]>dfn[now])
key[cnt][0]=i,key[cnt++][1]=now;
if (low[i]
low[now]=low[i];
}
else if (dfn[i]
low[now]=lev[i];
}
}
int key_edge(int n,int mat[][MAXN],int key[][2]){
int ret=0,i,dfn[MAXN],low[MAXN];
for (i=0;i
for (i=0;i
if (!dfn[i])
dfn[i]=1,bridge(n,mat,dfn,low,i,ret,key);
return ret;
}
2. 无向图关键点(dfs邻接阵形式)
//无向图的关键点,dfs邻接阵形式,O(n^2)
//返回关键点个数,key[]返回点集
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 110
void search(int n,int mat[][MAXN],int* dfn,int* low,int now,int& ret,int* key,int& cnt,int root,int& rd,int* bb){
int i;
dfn[now]=low[now]=++cnt;
for (i=0;i
if (mat[now][i]){
if (!dfn[i]){
search(n,mat,dfn,low,i,ret,key,cnt,root,rd,bb);
if (low[i]
low[now]=low[i];
if (low[i]>=dfn[now]){
if (now!=root&&!bb[now])
key[ret++]=now,bb[now]=1;
else if(now==root)
rd++;
}
}
else if (dfn[i]
low[now]=dfn[i];
}
}
int key_vertex(int n,int mat[][MAXN],int* key){
int ret=0,i,cnt,rd,dfn[MAXN],low[MAXN],bb[MAXN];
for (i=0;i
for (cnt=i=0;i
if (!dfn[i]){
rd=0;
search(n,mat,dfn,low,i,ret,key,cnt,i,rd,bb);
if (rd>1&&!bb[i])
key[ret++]=i,bb[i]=1;
}
return ret;
}
3. 无向图块(bfs邻接阵形式)
//无向图的块,dfs邻接阵形式,O(n^2)
//每产生一个块调用dummy
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
#include
void dummy(int n,int* a){
for (int i=0;i
cout<
}
void search(int n,int mat[][MAXN],int* dfn,int* low,int now,int& cnt,int* st,int& sp){
int i,m,a[MAXN];
dfn[st[sp++]=now]=low[now]=++cnt;
for (i=0;i
if (mat[now][i]){
if (!dfn[i]){
search(n,mat,dfn,low,i,cnt,st,sp);
if (low[i]
low[now]=low[i];
if (low[i]>=dfn[now]){
for (st[sp]=-1,a[0]=now,m=1;st[sp]!=i;a[m++]=st[--sp]);
dummy(m,a);
}
}
else if (dfn[i]
low[now]=dfn[i];
}
}
void block(int n,int mat[][MAXN]){
int i,cnt,dfn[MAXN],low[MAXN],st[MAXN],sp=0;
for (i=0;i
for (cnt=i=0;i
if (!dfn[i])
search(n,mat,dfn,low,i,cnt,st,sp);
}
4. 无向图连通分支(bfs邻接阵形式)
//无向图连通分支,bfs邻接阵形式,O(n^2)
//返回分支数,id返回1..分支数的值
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
int find_components(int n,int mat[][MAXN],int* id){
int ret,k,i,j,m;
for (k=0;k
for (ret=k=0;k
if (!id[k])
for (id[k]=-1,ret++,m=1;m;)
for (m=i=0;i
if (id[i]==-1)
for (m++,id[i]=ret,j=0;j
if (!id[j]&&mat[i][j])
id[j]=-1;
return ret;
}
5. 无向图连通分支(dfs邻接阵形式)
//无向图连通分支,dfs邻接阵形式,O(n^2)
//返回分支数,id返回1..分支数的值
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
void floodfill(int n,int mat[][MAXN],int* id,int now,int tag){
int i;
for (id[now]=tag,i=0;i
if (!id[i]&&mat[now][i])
floodfill(n,mat,id,i,tag);
}
int find_components(int n,int mat[][MAXN],int* id){
int ret,i;
for (i=0;i
for (ret=i=0;i
if (!id[i])
floodfill(n,mat,id,i,++ret);
return ret;
}
6. 有向图强连通分支(bfs邻接阵形式)
//有向图强连通分支,bfs邻接阵形式,O(n^2)
//返回分支数,id返回1..分支数的值
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
int find_components(int n,int mat[][MAXN],int* id){
int ret=0,a[MAXN],b[MAXN],c[MAXN],d[MAXN],i,j,k,t;
for (k=0;k
for (k=0;k
if (!id[k]){
for (i=0;i
a[i]=b[i]=c[i]=d[i]=0;
a[k]=b[k]=1;
for (t=1;t;)
for (t=i=0;i
if (a[i]&&!c[i])
for (c[i]=t=1,j=0;j
if (mat[i][j]&&!a[j])
a[j]=1;
if (b[i]&&!d[i])
for (d[i]=t=1,j=0;j
if (mat[j][i]&&!b[j])
b[j]=1;
}
for (ret++,i=0;i
if (a[i]&b[i])
id[i]=ret;
}
return ret;
}
7. 有向图强连通分支(dfs邻接阵形式)
//有向图强连通分支,dfs邻接阵形式,O(n^2)
//返回分支数,id返回1..分支数的值
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
void search(int n,int mat[][MAXN],int* dfn,int* low,int now,int& cnt,int& tag,int* id,int* st,int& sp){
int i,j;
dfn[st[sp++]=now]=low[now]=++cnt;
for (i=0;i
if (mat[now][i]){
if (!dfn[i]){
ssearch(n,mat,dfn,low,i,cnt,tag,id,st,sp);
if (low[i]
low[now]=low[i];
}
else if (dfn[i]
for (j=0;j
if (j
low[now]=dfn[i];
}
}
if (low[now]==dfn[now])
for (tag++;st[sp]!=now;id[st[--sp]]=tag);
}
int find_components(int n,int mat[][MAXN],int* id){
int ret=0,i,cnt,sp,st[MAXN],dfn[MAXN],low[MAXN];
for (i=0;i
for (sp=cnt=i=0;i
if (!dfn[i])
search(n,mat,dfn,low,i,cnt,ret,id,st,sp);
return ret;
}
8. 有向图最小点基(邻接阵形式)
//有向图最小点基,邻接阵形式,O(n^2)
//返回电集大小和点集
//传入图的大小n和邻接阵mat,不相邻点边权0
//需要调用强连通分支
#define MAXN 100
int base_vertex(int n,int mat[][MAXN],int* sets){
int ret=0,id[MAXN],v[MAXN],i,j;
j=find_components(n,mat,id);
for (i=0;i
for (i=0;i
for (j=0;j
if (id[i]!=id[j]&&mat[i][j])
v[id[j]-1]=0;
for (i=0;i
if (v[id[i]-1])
v[id[sets[ret++]=i]-1]=0;
return ret;
}
1.欧拉回路(邻接阵形式)
//求欧拉回路或欧拉路,邻接阵形式,复杂度O(n^2)
//返回路径长度,path返回路径(有向图时得到的是反向路径)
//传入图的大小n和邻接阵mat,不相邻点边权0
//可以有自环与重边,分为无向图和有向图
#define MAXN 100
void find_path_u(int n,int mat[][MAXN],int now,int& step,int* path){
int i;
for (i=n-1;i>=0;i--)
while (mat[now][i]){
mat[now][i]--,mat[i][now]--;
find_path_u(n,mat,i,step,path);
}
path[step++]=now;
}
void find_path_d(int n,int mat[][MAXN],int now,int& step,int* path){
int i;
for (i=n-1;i>=0;i--)
while (mat[now][i]){
mat[now][i]--;
find_path_d(n,mat,i,step,path);
}
path[step++]=now;
}
int euclid_path(int n,int mat[][MAXN],int start,int* path){
int ret=0;
find_path_u(n,mat,start,ret,path);
// find_path_d(n,mat,start,ret,path);
return ret;
}
2. 前序表转化
//将用边表示的树转化为前序表示的树
//传入节点数n和邻接表list[],邻接表必须是双向的,会在函数中释放
//pre[]返回前序表,map[]返回前序表中的节点到原来节点的映射
#define MAXN 10000
struct node{
int to;
node* next;
};
void prenode(int n,node* list[],int* pre,int* map,int* v,int now,int last,int& id){
node* t;
int p=id++;
for (v[map[p]=now]=1,pre[p]=last;list[now];){
t=list[now],list[now]=t->next;
if (!v[t->to])
prenode(n,list,pre,map,v,t->to,p,id);
}
}
void makepre(int n,node* list[],int* pre,int* map){
int v[MAXN],id=0,i;
for (i=0;i
prenode(n,list,pre,map,v,0,-1,id);
}
3. 树的优化算法
//最大顶点独立集
int max_node_independent(int n,int* pre,int* set){
int c[MAXN],i,ret=0;
for (i=0;i
c[i]=set[i]=0;
for (i=n-1;i>=0;i--)
if (!c[i]){
set[i]=1;
if (pre[i]!=-1)
c[pre[i]]=1;
ret++;
}
return ret;
}
//最大边独立集
int max_edge_independent(int n,int* pre,int* set){
int c[MAXN],i,ret=0;
for (i=0;i
c[i]=set[i]=0;
for (i=n-1;i>=0;i--)
if (!c[i]&&pre[i]!=-1&&!c[pre[i]]){
set[i]=1;
c[pre[i]]=1;
ret++;
}
return ret;
}
//最小顶点覆盖集
int min_node_cover(int n,int* pre,int* set){
int c[MAXN],i,ret=0;
for (i=0;i
c[i]=set[i]=0;
for (i=n-1;i>=0;i--)
if (!c[i]&&pre[i]!=-1&&!c[pre[i]]){
set[i]=1;
c[pre[i]]=1;
ret++;
}
return ret;
}
//最小顶点支配集
int min_node_dominant(int n,int* pre,int* set){
int c[MAXN],i,ret=0;
for (i=0;i
c[i]=set[i]=0;
for (i=n-1;i>=0;i--)
if (!c[i]&&(pre[i]==-1||!set[pre[i]])){
if (pre[i]!=-1){
set[pre[i]]=1;
c[pre[i]]=1;
if (pre[pre[i]]!=-1)
c[pre[pre[i]]]=1;
}
else
set[i]=1;
ret++;
}
return ret;
}
4. 拓扑排序(邻接阵形式).
//拓扑排序,邻接阵形式,复杂度O(n^2)
//如果无法完成排序,返回0,否则返回1,ret返回有序点列
//传入图的大小n和邻接阵mat,不相邻点边权0
#define MAXN 100
int toposort(int n,int mat[][MAXN],int* ret){
int d[MAXN],i,j,k;
for (i=0;i
for (d[i]=j=0;j
for (k=0;k
for (i=0;d[i]&&i
if (i==n)
return 0;
for (d[i]=-1,j=0;j
d[j]-=mat[i][j];
}
return 1;
}
5. 最佳边割集
//最佳边割集
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink){
int v[MAXN],c[MAXN],p[MAXN],ret=0,i,j;
for (;;){
for (i=0;i
v[i]=c[i]=0;
for (c[source]=inf;;){
for (j=-1,i=0;i
if (!v[i]&&c[i]&&(j==-1||c[i]>c[j]))
j=i;
if (j<0) return ret;
if (j==sink) break;
for (v[j]=1,i=0;i
if (mat[j][i]>c[i]&&c[j]>c[i])
c[i]=mat[j][i]
}
for (ret+=j=c[i=sink];i!=source;i=p[i])
mat[p[i]][i]-=j,mat[i][p[i]]+=j;
}
}
int best_edge_cut(int n,int mat[][MAXN],int source,int sink,int set[][2],int& mincost){
int m0[MAXN][MAXN],m[MAXN][MAXN],i,j,k,l,ret=0,last;
if (source==sink)
return -1;
for (i=0;i
for (j=0;j
m0[i][j]=mat[i][j];
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
mincost=last=max_flow(n,m,source,sink);
for (k=0;k
for (l=0;l
if (m0[k][l]){
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
m[k][l]=0;
if (max_flow(n,m,source,sink)==last-mat[k][l]){
set[ret][0]=k;
set[ret++][1]=l;
m0[k][l]=0;
last-=mat[k][l];
}
}
return ret;
}
6. 最佳顶点割集
//最佳顶点割集
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink){
int v[MAXN],c[MAXN],p[MAXN],ret=0,i,j;
for (;;){
for (i=0;i
v[i]=c[i]=0;
for (c[source]=inf;;){
for (j=-1,i=0;i
if (!v[i]&&c[i]&&(j==-1||c[i]>c[j]))
j=i;
if (j<0) return ret;
if (j==sink) break;
for (v[j]=1,i=0;i
if (mat[j][i]>c[i]&&c[j]>c[i])
c[i]=mat[j][i]
}
for (ret+=j=c[i=sink];i!=source;i=p[i])
mat[p[i]][i]-=j,mat[i][p[i]]+=j;
}
}
int best_vertex_cut(int n,int mat[][MAXN],int* cost,int source,int sink,int* set,int& mincost){
int m0[MAXN][MAXN],m[MAXN][MAXN],i,j,k,ret=0,last;
if (source==sink||mat[source][sink])
return -1;
for (i=0;i
for (j=0;j
m0[i][j]=0;
for (i=0;i
for (j=0;j
if (mat[i][j])
m0[i][n+j]=inf;
for (i=0;i
m0[n+i][i]=cost[i];
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
mincost=last=max_flow(n+n,m,source,n+sink);
for (k=0;k
if (k!=source&&k!=sink){
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
m[n+k][k]=0;
if (max_flow(n+n,m,source,n+sink)==last-cost[k]){
set[ret++]=k;
m0[n+k][k]=0;
last-=cost[k];
}
}
return ret;
}
7. 最小边割集
//最小边割集
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink){
int v[MAXN],c[MAXN],p[MAXN],ret=0,i,j;
for (;;){
for (i=0;i
v[i]=c[i]=0;
for (c[source]=inf;;){
for (j=-1,i=0;i
if (!v[i]&&c[i]&&(j==-1||c[i]>c[j]))
j=i;
if (j<0) return ret;
if (j==sink) break;
for (v[j]=1,i=0;i
if (mat[j][i]>c[i]&&c[j]>c[i])
c[i]=mat[j][i]
}
for (ret+=j=c[i=sink];i!=source;i=p[i])
mat[p[i]][i]-=j,mat[i][p[i]]+=j;
}
}
int min_edge_cut(int n,int mat[][MAXN],int source,int sink,int set[][2]){
int m0[MAXN][MAXN],m[MAXN][MAXN],i,j,k,l,ret=0,last;
if (source==sink)
return -1;
for (i=0;i
for (j=0;j
m0[i][j]=(mat[i][j]!=0);
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
last=max_flow(n,m,source,sink);
for (k=0;k
for (l=0;l
if (m0[k][l]){
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
m[k][l]=0;
if (max_flow(n,m,source,sink)
set[ret][0]=k;
set[ret++][1]=l;
m0[k][l]=0;
last--;
}
}
return ret;
}
8. 最小顶点割集
//最小顶点割集
#define MAXN 100
#define inf 1000000000
int max_flow(int n,int mat[][MAXN],int source,int sink){
int v[MAXN],c[MAXN],p[MAXN],ret=0,i,j;
for (;;){
for (i=0;i
v[i]=c[i]=0;
for (c[source]=inf;;){
for (j=-1,i=0;i
if (!v[i]&&c[i]&&(j==-1||c[i]>c[j]))
j=i;
if (j<0) return ret;
if (j==sink) break;
for (v[j]=1,i=0;i
if (mat[j][i]>c[i]&&c[j]>c[i])
c[i]=mat[j][i]
}
for (ret+=j=c[i=sink];i!=source;i=p[i])
mat[p[i]][i]-=j,mat[i][p[i]]+=j;
}
}
int min_vertex_cut(int n,int mat[][MAXN],int source,int sink,int* set){
int m0[MAXN][MAXN],m[MAXN][MAXN],i,j,k,ret=0,last;
if (source==sink||mat[source][sink])
return -1;
for (i=0;i
for (j=0;j
m0[i][j]=0;
for (i=0;i
for (j=0;j
if (mat[i][j])
m0[i][n+j]=inf;
for (i=0;i
m0[n+i][i]=1;
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
last=max_flow(n+n,m,source,n+sink);
for (k=0;k
if (k!=source&&k!=sink){
for (i=0;i
for (j=0;j
m[i][j]=m0[i][j];
m[n+k][k]=0;
if (max_flow(n+n,m,source,n+sink)
set[ret++]=k;
m0[n+k][k]=0;
last--;
}
}
return ret;
}
9. 最小路径覆盖
//最小路径覆盖,O(n^3)
//求解最小的路径覆盖图中所有点,有向图无向图均适用
//注意此问题等价二分图最大匹配,可以用邻接表或正向表减小复杂度
//返回最小路径条数,pre返回前指针(起点-1),next返回后指针(终点-1)
#include
#define MAXN 310
#define _clr(x) memset(x,0xff,sizeof(int)*n)
int hungary(int n,int mat[][MAXN],int* match1,int* match2){
int s[MAXN],t[MAXN],p,q,ret=0,i,j,k;
for (_clr(match1),_clr(match2),i=0;i
for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)
for (k=s[p],j=0;j
if (mat[k][j]&&t[j]<0){
s[++q]=match2[j],t[j]=k;
if (s[q]<0)
for (p=j;p>=0;j=p)
match2[j]=k=t[j],p=match1[k],match1[k]=j;
}
return ret;
}
inline int path_cover(int n,int mat[][MAXN],int* pre,int* next){
return n-hungary(n,mat,next,pre);
}
1. 最大团(n小于64)(faster)
/**
* WishingBone's ACM/ICPC Routine Library
*
* maximum clique solver
*/
#include
using std::vector;
// clique solver calculates both size and consitution of maximum clique
// uses bit operation to accelerate searching
// graph size limit is 63, the graph should be undirected
// can optimize to calculate on each component, and sort on vertex degrees
// can be used to solve maximum independent set
class clique {
public:
static const long long ONE = 1;
static const long long MASK = (1 << 21) - 1;
char* bits;
int n, size, cmax[63];
long long mask[63], cons;
// initiate lookup table
clique() {
bits = new char[1 << 21];
bits[0] = 0;
for (int i = 1; i < 1 << 21; ++i) bits[i] = bits[i >> 1] + (i & 1);
}
~clique() {
delete bits;
}
// search routine
bool search(int step, int size, long long more, long long con);
// solve maximum clique and return size
int sizeClique(vector
// solve maximum clique and return constitution
vector
};
// search routine
// step is node id, size is current solution, more is available mask, cons is
constitution mask
bool clique::search(int step, int size, long long more, long long cons) {
if (step >= n) {
// a new solution reached
this->size = size;
this->cons = cons;
return true;
}
long long now = ONE << step;
if ((now & more) > 0) {
long long next = more & mask[step];
if (size + bits[next & MASK] + bits[(next >> 21) & MASK] + bits[next >>
42] >= this->size
&& size + cmax[step] > this->size) {
// the current node is in the clique
if (search(step + 1, size + 1, next, cons | now)) return true;
}
}
long long next = more & ~now;
if (size + bits[next & MASK] + bits[(next >> 21) & MASK] + bits[next >> 42]
> this->size) {
// the current node is not in the clique
if (search(step + 1, size, next, cons)) return true;
}
return false;
}
// solve maximum clique and return size
int clique::sizeClique(vector
n = mat.size();
// generate mask vectors
for (int i = 0; i < n; ++i) {
mask[i] = 0;
for (int j = 0; j < n; ++j) if (mat[i][j] > 0) mask[i] |= ONE << j;
}
size = 0;
for (int i = n - 1; i >= 0; --i) {
search(i + 1, 1, mask[i], ONE << i);
cmax[i] = size;
}
return size;
}
// solve maximum clique and return constitution
// calls sizeClique and restore cons
vector
sizeClique(mat);
vector
for (int i = 0; i < n; ++i) if ((cons & (ONE << i)) > 0) ret.push_back(i);
return ret;
}
2. 最大团
//最大团
//返回最大团大小和一个方案,传入图的大小n和邻接阵mat
//mat[i][j]为布尔量
#define MAXN 60
void clique(int n, int* u, int mat[][MAXN], int size, int& max, int& bb, int* res, int* rr, int* c) {
int i, j, vn, v[MAXN];
if (n) {
if (size + c[u[0]] <= max) return;
for (i = 0; i < n + size - max && i < n; ++ i) {
for (j = i + 1, vn = 0; j < n; ++ j)
if (mat[u[i]][u[j]])
v[vn ++] = u[j];
rr[size] = u[i];
clique(vn, v, mat, size + 1, max, bb, res, rr, c);
if (bb) return;
}
} else if (size > max) {
max = size;
for (i = 0; i < size; ++ i)
res[i] = rr[i];
bb = 1;
}
}
int maxclique(int n, int mat[][MAXN], int *ret) {
int max = 0, bb, c[MAXN], i, j;
int vn, v[MAXN], rr[MAXN];
for (c[i = n - 1] = 0; i >= 0; -- i) {
for (vn = 0, j = i + 1; j < n; ++ j)
if (mat[i][j])
v[vn ++] = j;
bb = 0;
rr[0] = i;
clique(vn, v, mat, 1, max, bb, ret, rr, c);
c[i] = max;
}
return max;
}
1. 排列组合生成
//gen_perm产生字典序排列P(n,m)
//gen_comb产生字典序组合C(n,m)
//gen_perm_swap产生相邻位对换全排列P(n,n)
//产生元素用1..n表示
//dummy为产生后调用的函数,传入a[]和n,a[0]..a[n-1]为一次产生的结果
#define MAXN 100
int count;
#include
void dummy(int* a,int n){
int i;
cout<
for (i=0;i
}
void _gen_perm(int* a,int n,int m,int l,int* temp,int* tag){
int i;
if (l==m)
dummy(temp,m);
else
for (i=0;i
if (!tag[i]){
temp[l]=a[i],tag[i]=1;
_gen_perm(a,n,m,l+1,temp,tag);
tag[i]=0;
}
}
void gen_perm(int n,int m){
int a[MAXN],temp[MAXN],tag[MAXN]={0},i;
for (i=0;i
a[i]=i+1;
_gen_perm(a,n,m,0,temp,tag);
}
void _gen_comb(int* a,int s,int e,int m,int& count,int* temp){
int i;
if (!m)
dummy(temp,count);
else
for (i=s;i<=e-m+1;i++){
temp[count++]=a[i];
_gen_comb(a,i+1,e,m-1,count,temp);
count--;
}
}
void gen_comb(int n,int m){
int a[MAXN],temp[MAXN],count=0,i;
for (i=0;i
a[i]=i+1;
_gen_comb(a,0,n-1,m,count,temp);
}
void _gen_perm_swap(int* a,int n,int l,int* pos,int* dir){
int i,p1,p2,t;
if (l==n)
dummy(a,n);
else{
_gen_perm_swap(a,n,l+1,pos,dir);
for (i=0;i
p2=(p1=pos[l])+dir[l];
t=a[p1],a[p1]=a[p2],a[p2]=t;
pos[a[p1]-1]=p1,pos[a[p2]-1]=p2;
_gen_perm_swap(a,n,l+1,pos,dir);
}
dir[l]=-dir[l];
}
}
void gen_perm_swap(int n){
int a[MAXN],pos[MAXN],dir[MAXN],i;
for (i=0;i
a[i]=i+1,pos[i]=i,dir[i]=-1;
_gen_perm_swap(a,n,0,pos,dir);
}
2. 生成gray码
//生成reflected gray code
//每次调用gray取得下一个码
//000...000是第一个码,100...000是最后一个码
void gray(int n,int *code){
int t=0,i;
for (i=0;i
if (t&1)
for (n--;!code[n];n--);
code[n-1]=1-code[n-1];
}
3. 置换(polya)
//求置换的循环节,polya原理
//perm[0..n-1]为0..n-1的一个置换(排列)
//返回置换最小周期,num返回循环节个数
#define MAXN 1000
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int polya(int* perm,int n,int& num){
int i,j,p,v[MAXN]={0},ret=1;
for (num=i=0;i
if (!v[i]){
for (num++,j=0,p=i;!v[p=perm[p]];j++)
v[p]=1;
ret*=j/gcd(ret,j);
}
return ret;
}
4. 字典序全排列
//字典序全排列与序号的转换
int perm2num(int n,int *p){
int i,j,ret=0,k=1;
for (i=n-2;i>=0;k*=n-(i--))
for (j=i+1;j
if (p[j]
ret+=k;
return ret;
}
void num2perm(int n,int *p,int t){
int i,j;
for (i=n-1;i>=0;i--)
p[i]=t%(n-i),t/=n-i;
for (i=n-1;i;i--)
for (j=i-1;j>=0;j--)
if (p[j]<=p[i])
p[i]++;
}
5. 字典序组合
//字典序组合与序号的转换
//comb为组合数C(n,m),必要时换成大数,注意处理C(n,m)=0|n
int comb(int n,int m){
int ret=1,i;
m=m<(n-m)?m:(n-m);
for (i=n-m+1;i<=n;ret*=(i++));
for (i=1;i<=m;ret/=(i++));
return m<0?0:ret;
}
int comb2num(int n,int m,int *c){
int ret=comb(n,m),i;
for (i=0;i
ret-=comb(n-c[i],m-i);
return ret;
}
void num2comb(int n,int m,int* c,int t){
int i,j=1,k;
for (i=0;i
for (;t>(k=comb(n-j,m-i-1));t-=k,j++);
}
6. 组合公式
1. C(m,n)=C(m,m-n)
2. C(m,n)=C(m-1,n)+C(m-1,n-1)
derangement D(n) = n!(1 - 1/1! + 1/2! - 1/3! + ... + (-1)^n/n!)
= (n-1)(D(n-2) - D(n-1))
Q(n) = D(n) + D(n-1)
求和公式,k = 1..n
1. sum( k ) = n(n+1)/2
2. sum( 2k-1 ) = n^2
3. sum( k^2 ) = n(n+1)(2n+1)/6
4. sum( (2k-1)^2 ) = n(4n^2-1)/3
5. sum( k^3 ) = (n(n+1)/2)^2
6. sum( (2k-1)^3 ) = n^2(2n^2-1)
7. sum( k^4 ) = n(n+1)(2n+1)(3n^2+3n-1)/30
8. sum( k^5 ) = n^2(n+1)^2(2n^2+2n-1)/12
9. sum( k(k+1) ) = n(n+1)(n+2)/3
10. sum( k(k+1)(k+2) ) = n(n+1)(n+2)(n+3)/4
12. sum( k(k+1)(k+2)(k+3) ) = n(n+1)(n+2)(n+3)(n+4)/5
1. 定积分计算(Romberg)
/* Romberg求定积分
输入:积分区间[a,b],被积函数f(x,y,z)
输出:积分结果
f(x,y,z)示例:
double f0( double x, double l, double t )
{
return sqrt(1.0+l*l*t*t*cos(t*x)*cos(t*x));
}
*/
double Integral(double a, double b, double (*f)(double x, double y, double z), double eps,
double l, double t)
double Romberg (double a, double b, double (*f)(double x, double y, double z), double eps,
double l, double t)
{
#define MAX_N 1000
int i, j, temp2, min;
double h, R[2][MAX_N], temp4;
for (i=0; i
R[0][i] = 0.0;
R[1][i] = 0.0;
}
h = b-a;
min = (int)(log(h*10.0)/log(2.0)); //h should be at most 0.1
R[0][0] = ((*f)(a, l, t)+(*f)(b, l, t))*h*0.50;
i = 1;
temp2 = 1;
while (i
i++;
R[1][0] = 0.0;
for (j=1; j<=temp2; j++)
R[1][0] += (*f)(a+h*((double)j-0.50), l, t);
R[1][0] = (R[0][0] + h*R[1][0])*0.50;
temp4 = 4.0;
for (j=1; j
R[1][j] = R[1][j-1] + (R[1][j-1]-R[0][j-1])/(temp4-1.0);
temp4 *= 4.0;
}
if ((fabs(R[1][i-1]-R[0][i-2])
return R[1][i-1];
h *= 0.50;
temp2 *= 2;
for (j=0; j
R[0][j] = R[1][j];
}
return R[1][MAX_N-1];
}
double Integral(double a, double b, double (*f)(double x, double y, double z), double eps,
double l, double t)
{
#define pi 3.1415926535897932
int n;
double R, p, res;
n = (int)(floor)(b * t * 0.50 / pi);
p = 2.0 * pi / t;
res = b - (double)n * p;
if (n)
R = Romberg (a, p, f0, eps/(double)n, l, t);
R = R * (double)n + Romberg( 0.0, res, f0, eps, l, t );
return R/100.0;
}
2. 多项式求根(牛顿法)
/* 牛顿法解多项式的根
输入:多项式系数c[],多项式度数n,求在[a,b]间的根
输出:根
要求保证[a,b]间有根
*/
double fabs( double x )
{
return (x<0)? -x : x;
}
double f(int m, double c[], double x)
{
int i;
double p = c[m];
for (i=m; i>0; i--)
p = p*x + c[i-1];
return p;
}
int newton(double x0, double *r,
double c[], double cp[], int n,
double a, double b, double eps)
{
int MAX_ITERATION = 1000;
int i = 1;
double x1, x2, fp, eps2 = eps/10.0;
x1 = x0;
while (i < MAX_ITERATION) {
x2 = f(n, c, x1);
fp = f(n-1, cp, x1);
if ((fabs(fp)<0.000000001) && (fabs(x2)>1.0))
return 0;
x2 = x1 - x2/fp;
if (fabs(x1-x2)
if (x2b)
return 0;
*r = x2;
return 1;
}
x1 = x2;
i++;
}
return 0;
}
double Polynomial_Root(double c[], int n, double a, double b, double eps)
{
double *cp;
int i;
double root;
cp = (double *)calloc(n, sizeof(double));
for (i=n-1; i>=0; i--) {
cp[i] = (i+1)*c[i+1];
}
if (a>b) {
root = a; a = b; b = root;
}
if ((!newton(a, &root, c, cp, n, a, b, eps)) &&
(!newton(b, &root, c, cp, n, a, b, eps)))
newton((a+b)*0.5, &root, c, cp, n, a, b, eps);
free(cp);
if (fabs(root)
return fabs(root);
else
return root;
}
3. 周期性方程(追赶法)
/* 追赶法解周期性方程
周期性方程定义:| a1 b1 c1 ... | | | = x1
| a2 b2 c2 ... | | | = x2
| ... | * | X | = ...
| cn-1 ... an-1 bn-1 | | | = xn-1
| bn cn an | | | = xn
输入:a[],b[],c[],x[]
输出:求解结果X在x[]中
*/
void run()
{
c[0] /= b[0]; a[0] /= b[0]; x[0] /= b[0];
for (int i = 1; i < N - 1; i ++) {
double temp = b[i] - a[i] * c[i - 1];
c[i] /= temp;
x[i] = (x[i] - a[i] * x[i - 1]) / temp;
a[i] = -a[i] * a[i - 1] / temp;
}
a[N - 2] = -a[N - 2] - c[N - 2];
for (int i = N - 3; i >= 0; i --) {
a[i] = -a[i] - c[i] * a[i + 1];
x[i] -= c[i] * x[i + 1];
}
x[N - 1] -= (c[N - 1] * x[0] + a[N - 1] * x[N - 2]);
x[N - 1] /= (c[N - 1] * a[0] + a[N - 1] * a[N - 2] + b[N - 1]);
for (int i = N - 2; i >= 0; i --)
x[i] += a[i] * x[N - 1];
}
1. 多边形
#include
#include
#define MAXN 1000
#define offset 10000
#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))
#define _sign(x) ((x)>eps?1:((x)<-eps?2:0))
struct point{double x,y;};
struct line{point a,b;};
double xmult(point p1,point p2,point p0){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
//判定凸多边形,顶点按顺时针或逆时针给出,允许相邻边共线
int is_convex(int n,point* p){
int i,s[3]={1,1,1};
for (i=0;i
s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0;
return s[1]|s[2];
}
//判定凸多边形,顶点按顺时针或逆时针给出,不允许相邻边共线
int is_convex_v2(int n,point* p){
int i,s[3]={1,1,1};
for (i=0;i
s[_sign(xmult(p[(i+1)%n],p[(i+2)%n],p[i]))]=0;
return s[0]&&s[1]|s[2];
}
//判点在凸多边形内或多边形边上,顶点按顺时针或逆时针给出
int inside_convex(point q,int n,point* p){
int i,s[3]={1,1,1};
for (i=0;i
s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;
return s[1]|s[2];
}
//判点在凸多边形内,顶点按顺时针或逆时针给出,在多边形边上返回0
int inside_convex_v2(point q,int n,point* p){
int i,s[3]={1,1,1};
for (i=0;i
s[_sign(xmult(p[(i+1)%n],q,p[i]))]=0;
return s[0]&&s[1]|s[2];
}
//判点在任意多边形内,顶点按顺时针或逆时针给出
//on_edge表示点在多边形边上时的返回值,offset为多边形坐标上限