ACM代码库

目录

一.数论... 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 <string.h>

#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<len;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<d;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<k;i++)

                   n*=w[i];

         for (i=0;i<k;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越高失败概率越低,一般取1050

#include <stdlib.h>

#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<iostream>

#include<cstdio>

#include<cmath>

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 <cmath>

#include <iostream>

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<t;++i)isprime[i]=2863311530;

    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 <string.h>

#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<m;ret+=(match1[i++]>=0))

                   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 <string.h>

#include <vector>

#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<int> e[MAXN];

         //生成邻接表(只需一边)

         for(i=0;i<m;++i)

                   for(j=0;j<n;++j)

                            if (mat[i][j]) e[i].push_back(j);

         for (_clr(match1),_clr(match2),i=0;i<m;ret+=(match1[i++]>=0))

                   for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)

                            for(r=0,k=s[p];r<e[k].size()&&match1[i]<0;++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 <string.h>

#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<m;ret+=(match1[i++]>=0))

                   for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)

                            for (k=s[p],j=0;j<n&&match1[i]<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 <string.h>

#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<m;ret+=(match1[i++]>=0))

                   for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)

                            for (l=list[k=s[p]];l<list[k+1]&&match1[i]<0;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 <string.h>

#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<m;i++)

                   for (l1[i]=-inf,j=0;j<n;j++)

                            l1[i]=mat[i][j]>l1[i]?mat[i][j]:l1[i];

         for (i=0;i<n;l2[i++]=0);

         for (_clr(match1),_clr(match2),i=0;i<m;i++){

                   for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)

                            for (k=s[p],j=0;j<n&&match1[i]<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<n;j++)

                                               if (t[j]<0&&l1[s[k]]+l2[j]-mat[s[k]][j]<p)

                                                        p=l1[s[k]]+l2[j]-mat[s[k]][j];

                            for (j=0;j<n;l2[j]+=t[j]<0?0:p,j++);

                            for (k=0;k<=q;l1[s[k++]]-=p);

                   }

         }

         for (i=0;i<m;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<n;i++)

         v[i]=0,match[i]=-1;

         for (i=0,j=n;i<n&&j>=2;)

                   if (match[i]<0&&aug(n,list,match,v,i))

                            i=0,j-=2;

                   else

                            i++;

         for (i=j=0;i<n;i++)

                   j+=(match[i]>=0);

         return j/2;

}

7. 一般图匹配(邻接表形式,邻接阵接口)

//一般图最大匹配,邻接表形式,复杂度O(n*e)

//返回匹配顶点对数,match返回匹配,未匹配顶点match值为-1

//传入图的顶点数n和邻接表list

#include <vector>

#define MAXN 100

 

int aug(int n,vector<int> list[],int* match,int* v,int now){

         int t,ret=0,r;

         v[now]=1;

//       for (e=list[now];e;e=e->next)

         for (r=0;r<list[now].size();++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<int> list[MAXN];

         for (i=0;i<n;i++)

                   for (j=0;j<n;j++)

                            if (mat[i][j]) list[i].push_back(j);

         for (i=0;i<n;i++)

         v[i]=0,match[i]=-1;

         for (i=0,j=n;i<n&&j>=2;)

                   if (match[i]<0&&aug(n,list,match,v,i))

                            i=0,j-=2;

                   else

                            i++;

         for (i=j=0;i<n;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<n;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<n;i++)

         v[i]=0,match[i]=-1;

         for (i=0,j=n;i<n&&j>=2;)

                   if (match[i]<0&&aug(n,mat,match,v,i))

                            i=0,j-=2;

                   else

                            i++;

         for (i=j=0;i<n;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<list[now+1];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<n;i++)

         v[i]=0,match[i]=-1;

         for (i=0,j=n;i<n&&j>=2;)

                   if (match[i]<0&&aug(n,list,buf,match,v,i))

                            i=0,j-=2;

                   else

                            i++;

         for (i=j=0;i<n;i++)

                   j+=(match[i]>=0);

         return j/2;

}

三.图论_生成树

1. 最小生成树(kruskal邻接表形式)

//无向图最小生成树,kruskal算法,邻接表形式,复杂度O(mlogm)

//返回最小生成树的长度,传入图的大小n和邻接表list

//可更改边权的类型,edge[][2]返回树的构造,用边集表示

//如果图不连通,则对各连通分支构造最小生成树,返回总长度

#include <string.h>

#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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);

                   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<n;i++)

                   for (t=list[i];t;t=t->next)

                            if (i<t->to)

                                     e.a=i,e.b=t->to,e.len=t->len,h.ins(e);

         while (m<n-1&&h.del(e))

                   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 <string.h>

#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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);

                   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<n;i++)

                   for (j=list[i];j<list[i+1];j++)

                            if (i<buf[j].to)

                                     e.a=i,e.b=buf[j].to,e.len=buf[j].len,h.ins(e);

         while (m<n-1&&h.del(e))

                   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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);

                   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<n;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<min[t->to])

                                               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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);

                   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<n;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<list[i+1];j++)

                                     if (!v[buf[j].to]&&buf[j].len<min[buf[j].to])

                                               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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n;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<min[t->to])

                                     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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n;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<list[i+1];j++)

                            if (!v[buf[j].to]&&buf[j].len<min[buf[j].to])

                                     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<n;i++)

                   min[i]=inf,v[i]=0,pre[i]=-1;

         for (min[j=0]=0;j<n;j++){

                   for (k=-1,i=0;i<n;i++)

                            if (!v[i]&&(k==-1||min[i]<min[k]))

                                     k=i;

                   for (v[k]=1,ret+=min[k],i=0;i<n;i++)

                            if (!v[i]&&mat[k][i]<min[i])

                                     min[i]=mat[pre[i]=k][i];

         }

         return ret;

}

8. 最小树形图(邻接阵形式)

//多源最小树形图,edmonds算法,邻接阵形式,复杂度O(n^3)

//返回最小生成树的长度,构造失败返回负值

//传入图的大小n和邻接阵mat,不相邻点边权inf

//可更改边权的类型,pre[]返回树的构造,用父结点表示

//传入时pre[]数组清零,-1标出源点

#include <string.h>

#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<n;l[i]=i,i++);

         do{

                   memset(c,0,sizeof(c)),memset(p,0xff,sizeof(p));

                   for (t=m,i=0;i<m;c[i][i]=1,i++);

                   for (i=0;i<t;i++)

                            if (l[i]==i&&pre[i]!=-1){

                                     for (j=0;j<m;j++)

                                               if (l[j]==j&&i!=j&&mat[j][i]<inf&&(p[i]==-1||mat[j][i]<mat[p[i]][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<m;j++)

                                                                 if (l[j]==j){

                                                                           if (mat[j][k]-mat[p[k]][k]<mat[j][m])

                                                                                    mat[j][m]=mat[j][k]-mat[p[k]][k];

                                                                           if (mat[k][j]<mat[m][j])

                                                                                    mat[m][j]=mat[k][j];

                                                                 }

                                               c[m][m]=1,l[m]=m,m++;

                                     }

                                      for (j=0;j<m;j++)

                                               if (c[i][j])

                                                        for (k=p[i];k!=-1&&l[k]==k;c[k][j]=1,k=p[k]);

                            }

         }

         while (t<m);

         for (;m-->n;pre[k]=pre[m])

                   for (i=0;i<m;i++)

                            if (l[i]==m){

                                     for (j=0;j<m;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<n;i++)

                   if (pre[i]!=-1)

                            ret+=mat[pre[i]][i];

         return ret;

}

四.图论_网络流

1. 上下界最大流(邻接表形式)

//求上下界网络最大流,邻接表形式

//返回最大流量,-1表示无可行流,flow返回每条边的流量

//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink

//MAXN应比最大结点数多2,无可行流返回-1mat未复原!

 

#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<int> e[MAXN];       

         for (i=0;i<n;i++)

                   for (e[i].clear(),j=0;j<n;j++)

                            if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);

         for (;;){

                   for (i=0;i<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (r=0;r<e[t].size();++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]<j?d[t]:j;

                                     else if (!pre[i]&&(j=flow[i][t]))

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                            }

                   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<n;j+=flow[source][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<n;i++)

                   for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;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<n+2;i++)

                   for (j=0;j<n+2;flow[i][j++]=0);

         _max_flow(n+2,mat,n,n+1,flow);

         for (i=0;i<n;i++)

                   if (flow[n][i]<mat[n][i]) return -1;

         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<n;i++)

                   for (j=0;j<n;j++)

                            mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];

         for (j=i=0;i<n;j+=flow[source][i++]);

         return j;

}

2. 上下界最大流(邻接阵形式)

//求上下界网络最大流,邻接阵形式

//返回最大流量,-1表示无可行流,flow返回每条边的流量

//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink

//MAXN应比最大结点数多2,无可行流返回-1mat未复原!

 

#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<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (i=0;i<n;i++)

                                     if (!pre[i]&&j=mat[t][i]-flow[t][i])

                                               pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;

                                     else if (!pre[i]&&j=flow[i][t])

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                   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<n;i++)

                   for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;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<n+2;i++)

                   for (j=0;j<n+2;flow[i][j++]=0);

         _max_flow(n+2,mat,n,n+1,flow);

         for (i=0;i<n;i++)

                   if (flow[n][i]<mat[n][i]) return -1;

         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<n;i++)

                   for (j=0;j<n;j++)

                            mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];

         for (j=i=0;i<n;j+=flow[source][i++]);

         return j;

}

3. 上下界最小流(邻接表形式)

//求上下界网络最小流,邻接阵形式

//返回最大流量,-1表示无可行流,flow返回每条边的流量

//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink

//MAXN应比最大结点数多2,无可行流返回-1mat未复原!

 

#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<int> e[MAXN];       

         for (i=0;i<n;i++)

                   for (e[i].clear(),j=0;j<n;j++)

                            if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);

         for (;;){

                   for (i=0;i<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (r=0;r<e[t].size();++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]<j?d[t]:j;

                                     else if (!pre[i]&&(j=flow[i][t]))

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                            }

                   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<n;j+=flow[source][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<n;i++)

                   for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;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<n+2;i++)

                   for (j=0;j<n+2;flow[i][j++]=0);

         _max_flow(n+2,mat,n,n+1,flow);

         for (i=0;i<n;i++)

                   if (flow[n][i]<mat[n][i]) return -1;

         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<n;i++)

                   for (j=0;j<n;j++)

                            mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];

         for (j=i=0;i<n;j+=flow[source][i++]);

         return j;

}

4. 上下界最小流(邻接阵形式)

//求上下界网络最小流,邻接阵形式

//返回最大流量,-1表示无可行流,flow返回每条边的流量

//传入网络节点数n,容量mat,流量下界bf,源点source,汇点sink

//MAXN应比最大结点数多2,无可行流返回-1mat未复原!

 

#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<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (i=0;i<n;i++)

                                     if (!pre[i]&&j=mat[t][i]-flow[t][i])

                                               pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;

                                     else if (!pre[i]&&j=flow[i][t])

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                   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<n;i++)

                   for (mat[n][i]=mat[i][n]=mat[n+1][i]=mat[i][n+1]=j=0;j<n;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<n+2;i++)

                   for (j=0;j<n+2;flow[i][j++]=0);

         _max_flow(n+2,mat,n,n+1,flow);

         for (i=0;i<n;i++)

                   if (flow[n][i]<mat[n][i]) return -1;

         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<n;i++)

                   for (j=0;j<n;j++)

                            mat[i][j]+=bf[i][j],flow[i][j]+=bf[i][j];

         for (j=i=0;i<n;j+=flow[source][i++]);

         return j;

}

5. 最大流(邻接表形式)

//求网络最大流,邻接表形式

//返回最大流量,flow返回每条边的流量

//传入网络节点数n,容量mat,邻接表list,源点source,汇点sink

//list[i](vector<int>)存放所有以i相邻的点,包括反向边!!!

 

#define MAXN 100

#define inf 1000000000

 

int max_flow(int n,int mat[][MAXN],vector<int> list[],int source,int sink,int flow[][MAXN]){

         int pre[MAXN],que[MAXN],d[MAXN],p,q,t,i,j,r;

         if (source==sink) return inf;

         for (i=0;i<n;i++)

                   for (j=0;j<n;flow[i][j++]=0);

         for (;;){

                   for (i=0;i<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (r=0;r<list[t].size();++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]<j?d[t]:j;

                                     else if (!pre[i]&&j=flow[i][t])

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                            }

                   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<n;j+=flow[source][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<int> e[MAXN];       

         if (source==sink) return inf;

         for (i=0;i<n;i++)

                   for (j=0;j<n;flow[i][j++]=0);

         //e[i]存放所有以i相邻的点,包括反向边!!!

         for (i=0;i<n;i++)

                   for (e[i].clear(),j=0;j<n;j++)

                            if (mat[i][j]) e[i].push_back(j),e[j].push_back(i);

         for (;;){

                   for (i=0;i<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (r=0;r<e[t].size();++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]<j?d[t]:j;

                                     else if (!pre[i]&&(j=flow[i][t]))

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                            }

                   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<n;j+=flow[source][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<n;i++)

                   for (j=0;j<n;flow[i][j++]=0);

         for (;;){

                   for (i=0;i<n;pre[i++]=0);

                   pre[t=source]=source+1,d[t]=inf;

                   for (p=q=0;p<=q&&!pre[sink];t=que[p++])

                            for (i=0;i<n;i++)

                                     if (!pre[i]&&j=mat[t][i]-flow[t][i])

                                               pre[que[q++]=i]=t+1,d[i]=d[t]<j?d[t]:j;

                                     else if (!pre[i]&&j=flow[i][t])

                                               pre[que[q++]=i]=-t-1,d[i]=d[t]<j?d[t]:j;

                   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<n;j+=flow[source][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<n;i++)

                            v[i]=c[i]=0;

                   for (c[source]=inf;;){

                            for (j=-1,i=0;i<n;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<n;i++)

                                     if (mat[j][i]>c[i]&&c[j]>c[i])

                                               c[i]=mat[j][i]<c[j]?mat[j][i]:c[j],p[i]=j;

                   }

                   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<n;i++)

                   for (j=0;j<n;flow[i][j++]=0);

         for (netcost=0;;){

                   for (i=0;i<n;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<n;t++)

                                     if (d[t])

                                               for (i=0;i<n;i++)

                                                        if (j=mat[t][i]-flow[t][i]&&min[t]+cost[t][i]<min[i])

                                                                 tag=1,min[i]=min[t]+cost[t][i],pre[i]=t+1,d[i]=d[t]<j?d[t]:j;

                                                        else if (j=flow[i][t]&&min[t]<inf&&min[t]-cost[i][t]<min[i])

                                                                 tag=1,min[i]=min[t]-cost[i][t],pre[i]=-t-1,d[i]=d[t]<j?d[t]:j;

                   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<n;j+=flow[source][i++]);

         return j;

}

. 图论_最短路径

1. 最短路径(单源bellman_ford邻接阵形式)

//单源最短路径,bellman_ford算法,邻接阵形式,复杂度O(n^3)

//求出源s到所有点的最短路经,传入图的大小n和邻接阵mat

//返回到各点最短距离min[]和路径pre[],pre[i]记录si路径上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<n;i++)

                   min[i]=inf,v[i]=0,pre[i]=-1;

         for (min[s]=0,j=0;j<n;j++){

                   for (k=-1,i=0;i<n;i++)

                            if (!v[i]&&(k==-1||min[i]<min[k]))

                                     k=i;

                   for (v[k]=1,i=0;i<n;i++)

                            if (!v[i]&&mat[k][i]>=0&&min[k]+mat[k][i]<min[i])

                                     min[i]=min[k]+mat[pre[i]=k][i];

         }

         for (tag=1,j=0;tag&&j<=n;j++)

                   for (tag=i=0;i<n;i++)

                            for (k=0;k<n;k++)

                                     if (min[k]+mat[k][i]<min[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]记录si路径上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<n;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]记录si路径上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<n;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<list[que[i]+1];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]记录si路径上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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);

                   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<n;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<min[t->to])

                                               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]记录si路径上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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[p]=h[c],p=c,c<<=1);

                   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<n;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<list[f+1];t++)

                                     if (!v[buf[t].to]&&min[f]+buf[t].len<min[buf[t].to])

                                               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]记录si路径上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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n;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<min[t->to])

                                     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]记录si路径上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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n&&_cp(h[c+=(c<n-1&&_cp(h[c+1],h[c]))],h[n]);h[map[ind[p]=ind[c]]=p]=h[c],p=c,c<<=1);

                   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<n;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<list[i+1];t++)

                            if (!v[buf[t].to]&&min[i]+buf[t].len<min[buf[t].to])

                                     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]记录si路径上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<n;i++)

                   min[i]=inf,v[i]=0,pre[i]=-1;

         for (min[s]=0,j=0;j<n;j++){

                   for (k=-1,i=0;i<n;i++)

                            if (!v[i]&&(k==-1||min[i]<min[k]))

                                     k=i;

                   for (v[k]=1,i=0;i<n;i++)

                            if (!v[i]&&min[k]+mat[k][i]<min[i])

                                     min[i]=min[k]+mat[pre[i]=k][i];

         }

}

9. 最短路径(多源floyd_warshall邻接阵形式)

//多源最短路径,floyd_warshall算法,复杂度O(n^3)

//求出所有点对之间的最短路经,传入图的大小和邻接阵

//返回各点间最短距离min[]和路径pre[],pre[i][j]记录ij最短路径上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<n;i++)

                   for (j=0;j<n;j++)

                            min[i][j]=mat[i][j],pre[i][j]=(i==j)?-1:i;

         for (k=0;k<n;k++)

                   for (i=0;i<n;i++)

                            for (j=0;j<n;j++)

                                     if (min[i][k]+min[k][j]<min[i][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<n;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[now]=low[i];

                            }

                            else if (dfn[i]<dfn[now]-1&&dfn[i]<low[now])

                                     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<n;dfn[i++]=0);

         for (i=0;i<n;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<n;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[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])

                                     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<n;dfn[i++]=bb[i]=0);

         for (cnt=i=0;i<n;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 <iostream.h>

void dummy(int n,int* a){

         for (int i=0;i<n;i++)

                   cout<<a[i]<<' ';

         cout<<endl;

}

 

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<n;i++)

                   if (mat[now][i]){

                            if (!dfn[i]){

                                     search(n,mat,dfn,low,i,cnt,st,sp);

                                     if (low[i]<low[now])

                                               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])

                                     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<n;dfn[i++]=0);

         for (cnt=i=0;i<n;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<n;id[k++]=0);

   for (ret=k=0;k<n;k++)

            if (!id[k])

                      for (id[k]=-1,ret++,m=1;m;)

                               for (m=i=0;i<n;i++)

                                        if (id[i]==-1)

                                                  for (m++,id[i]=ret,j=0;j<n;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<n;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<n;id[i++]=0);

         for (ret=i=0;i<n;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<n;id[k++]=0);

         for (k=0;k<n;k++)

                   if (!id[k]){

                            for (i=0;i<n;i++)

                                     a[i]=b[i]=c[i]=d[i]=0;

                            a[k]=b[k]=1;

                            for (t=1;t;)

                                     for (t=i=0;i<n;i++){

                                               if (a[i]&&!c[i])

                                                        for (c[i]=t=1,j=0;j<n;j++)

                                                                 if (mat[i][j]&&!a[j])

                                                                           a[j]=1;

                                               if (b[i]&&!d[i])

                                                        for (d[i]=t=1,j=0;j<n;j++)

                                                                 if (mat[j][i]&&!b[j])

                                                                           b[j]=1;

                                     }

                            for (ret++,i=0;i<n;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<n;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[now]=low[i];

                            }

                            else if (dfn[i]<dfn[now]){

                                     for (j=0;j<sp&&st[j]!=i;j++);

                                     if (j<cnt&&dfn[i]<low[now])

                                               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<n;dfn[i++]=0);

         for (sp=cnt=i=0;i<n;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<j;v[i++]=1);

         for (i=0;i<n;i++)

                   for (j=0;j<n;j++)

                            if (id[i]!=id[j]&&mat[i][j])

                                     v[id[j]-1]=0;

         for (i=0;i<n;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<n;v[i++]=0);

         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<n;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<n;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<n;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<n;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<n;i++)

                   for (d[i]=j=0;j<n;d[i]+=mat[j++][i]);

         for (k=0;k<n;ret[k++]=i){

                   for (i=0;d[i]&&i<n;i++);

                   if (i==n)

                            return 0;

                   for (d[i]=-1,j=0;j<n;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<n;i++)

                            v[i]=c[i]=0;

                   for (c[source]=inf;;){

                            for (j=-1,i=0;i<n;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<n;i++)

                                     if (mat[j][i]>c[i]&&c[j]>c[i])

                                               c[i]=mat[j][i]<c[j]?mat[j][i]:c[j],p[i]=j;

                   }

                   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<n;i++)

                   for (j=0;j<n;j++)

                            m0[i][j]=mat[i][j];

         for (i=0;i<n;i++)

                   for (j=0;j<n;j++)

                            m[i][j]=m0[i][j];

         mincost=last=max_flow(n,m,source,sink);

         for (k=0;k<n&&last;k++)

                   for (l=0;l<n&&last;l++)

                            if (m0[k][l]){

                                     for (i=0;i<n+n;i++)

                                               for (j=0;j<n+n;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<n;i++)

                            v[i]=c[i]=0;

                   for (c[source]=inf;;){

                            for (j=-1,i=0;i<n;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<n;i++)

                                     if (mat[j][i]>c[i]&&c[j]>c[i])

                                               c[i]=mat[j][i]<c[j]?mat[j][i]:c[j],p[i]=j;

                   }

                   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<n+n;i++)

                   for (j=0;j<n+n;j++)

                            m0[i][j]=0;

         for (i=0;i<n;i++)

                   for (j=0;j<n;j++)

                            if (mat[i][j])

                                     m0[i][n+j]=inf;

         for (i=0;i<n;i++)

                   m0[n+i][i]=cost[i];

         for (i=0;i<n+n;i++)

                   for (j=0;j<n+n;j++)

                            m[i][j]=m0[i][j];

         mincost=last=max_flow(n+n,m,source,n+sink);

         for (k=0;k<n&&last;k++)

                   if (k!=source&&k!=sink){

                            for (i=0;i<n+n;i++)

                                     for (j=0;j<n+n;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<n;i++)

                            v[i]=c[i]=0;

                   for (c[source]=inf;;){

                            for (j=-1,i=0;i<n;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<n;i++)

                                     if (mat[j][i]>c[i]&&c[j]>c[i])

                                               c[i]=mat[j][i]<c[j]?mat[j][i]:c[j],p[i]=j;

                   }

                   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<n;i++)

                   for (j=0;j<n;j++)

                            m0[i][j]=(mat[i][j]!=0);

         for (i=0;i<n;i++)

                   for (j=0;j<n;j++)

                            m[i][j]=m0[i][j];

         last=max_flow(n,m,source,sink);

         for (k=0;k<n&&last;k++)

                   for (l=0;l<n&&last;l++)

                            if (m0[k][l]){

                                     for (i=0;i<n+n;i++)

                                               for (j=0;j<n+n;j++)

                                                        m[i][j]=m0[i][j];

                                     m[k][l]=0;

                                     if (max_flow(n,m,source,sink)<last){

                                               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<n;i++)

                            v[i]=c[i]=0;

                   for (c[source]=inf;;){

                            for (j=-1,i=0;i<n;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<n;i++)

                                     if (mat[j][i]>c[i]&&c[j]>c[i])

                                               c[i]=mat[j][i]<c[j]?mat[j][i]:c[j],p[i]=j;

                   }

                   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<n+n;i++)

                   for (j=0;j<n+n;j++)

                            m0[i][j]=0;

         for (i=0;i<n;i++)

                   for (j=0;j<n;j++)

                            if (mat[i][j])

                                     m0[i][n+j]=inf;

         for (i=0;i<n;i++)

                   m0[n+i][i]=1;

         for (i=0;i<n+n;i++)

                   for (j=0;j<n+n;j++)

                            m[i][j]=m0[i][j];

         last=max_flow(n+n,m,source,n+sink);

         for (k=0;k<n&&last;k++)

                   if (k!=source&&k!=sink){

                            for (i=0;i<n+n;i++)

                                     for (j=0;j<n+n;j++)

                                               m[i][j]=m0[i][j];

                            m[n+k][k]=0;

                            if (max_flow(n+n,m,source,n+sink)<last){

                                     set[ret++]=k;

                                     m0[n+k][k]=0;

                                     last--;

                            }

                   }

         return ret;

}

9. 最小路径覆盖

//最小路径覆盖,O(n^3)

//求解最小的路径覆盖图中所有点,有向图无向图均适用

//注意此问题等价二分图最大匹配,可以用邻接表或正向表减小复杂度

//返回最小路径条数,pre返回前指针(起点-1),next返回后指针(终点-1)

#include <string.h>

#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<n;ret+=(match1[i++]>=0))

                   for (_clr(t),s[p=q=0]=i;p<=q&&match1[i]<0;p++)

                            for (k=s[p],j=0;j<n&&match1[i]<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);

}

. 图论_NP搜索

1. 最大团(n小于64)(faster)

/**

 * WishingBone's ACM/ICPC Routine Library

 *

 * maximum clique solver

 */

 

#include <vector>

 

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<vector<int> >& mat);

    // solve maximum clique and return constitution

    vector<int> consClique(vector<vector<int> >& mat);

};

 

// 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<vector<int> >& mat) {

    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<int> clique::consClique(vector<vector<int> >& mat) {

    sizeClique(mat);

    vector<int> ret;

    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 <iostream.h>

void dummy(int* a,int n){

         int i;

         cout<<count++<<": ";

         for (i=0;i<n-1;i++)

                   cout<<a[i]<<' ';

         cout<<a[n-1]<<endl;

}

 

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<n;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<n;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++){

         &

你可能感兴趣的:(ACM代码库)