图论二
0、目录
最短路、最小生成树、LCA
(参考自白皮)
1、最短路
1.1、Floyd
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
mat[i][j]=INF;
if(i==j) mat[i][j]=0;
pre[i][j]=i;
}
}
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
vector<int> path;
path.push_back(t);
while(pre[s][t]!=s) {
path.pb(pre[s][t]);
t=pre[s][t];
}
path.push_back(s);
reverse(path.begin(),path.end());
1.2、Dijkstra
struct Edge{
int u,v,d;
};
struct HeapNode{
int d,u;
HeapNode(int d,int u):d(d),u(u){}
bool operator < (const HeapNode& tmp) const {
return d>tmp.d;
}
};
struct Dijkstra{
int n,m;
vector<Edge> egs;
vector<int> G[maxn];
bool done[maxn];
int d[maxn];
int p[maxn];
void init(int n){
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
egs.clear();
}
void addEdge(int u,int v,int d){
egs.push_back(Edge(u,v,d));
m=egs.size();
G[u].push_back(m-1);
}
void dijkstra(int s){
priority_queue<HeapNode> Q;
for(int i=0;i<n;i++) d[i]=INF;
d[s]=0;
memset(done,0,sizeof(done));
Q.push(HeapNode(0,s));
while(!Q.empty()){
HeapNode x=Q.top(); Q.pop();
int u=x.u;
if(done[u]) continue;
done[u]=1;
for(int i=0;i<G[u].size();i++){
Edge& e=egs[G[u][i]];
if(d[e.v]>d[u]+e.d){
d[e.v]=d[u]+e.d;
p[e.v]=G[u][i];
Q.push(HeapNode(d[e.v],e.v));
}
}
}
}
};
1.3、Spfa
struct Spfa{
int n,m;
vector<Edge> egs;
vector<int> G[maxn];
bool inq[maxn];
int d[maxn];
int p[maxn];
int cnt[maxn];
void init(int n){
this->n=n;
for(int i=0;i<n;i++) G[i].clear();
egs.clear();
}
void addEdge(int u,int v,int d){
egs.push_back(Edge(u,v,d));
m=egs.size();
G[u].push_back(m-1);
}
bool spfa(int s){
queue<int> Q;
memset(inq,0,sizeof(inq));
memset(cnt,0,sizeof(cnt));
for(int i=0;i<n;i++) d[i]=INF;
d[s]=0,inq[s]=true,Q.push(s);
while(!Q.empty()){
int u=Q.front(); Q.pop();
inq[u]=false;
for(int i=0;i<G[u].size();i++){
Edge& e=egs[G[u][i]];
if(d[e.v]>d[u]+e.d){
d[e.v]=d[u]+e.d;
p[e.v]=G[u][i];
if(!inq[e.v]){
Q.push(e.v),inq[e.v]=true;
if(++cnt[e.v]>n) return false;
}
}
}
}
return true;
}
};
2、最小生成树
2.0、两个性质
- 切割性质:假定所有的边权均不相等。设S为既非空集也非全集的V的子集,边e是满足一个端点在S内,另一个端点不在S内的所有边中权值最小的一个,则图G的所有最小生成树均包含e。
- 回路性质:假定所有的边权均不相同。设C是图G中的任意回路,边e是C上权值最大的边,则图G的所有最小生成树均不包含e。
2.1、无相图
/*kruskal*/
int fa[maxn];
int find(int x){ return fa[x]=fa[x]==x?x:find(fa[x]); }
int kruskal(){
int ret=0;
for(int i=0;i<maxn;i++) fa[i]=i;
sort(egs,egs+m);
for(int i=0;i<m;i++){
Edge& e=egs[i];
int pu=find(e.u);
int pv=find(e.v);
if(pu!=pv){
fa[pv]=pu;
ret+=e.w;
}
}
return ret;
}
2.2、有向图(最小树形图)
LL in[maxn];
int id[maxn], vis[maxn], pre[maxn];
LL Directed_MST(int rt) {
LL ret = 0;
while (1) {
//求最小入度边
for (int i = 0; i < n; i++) in[i] = INF;
for (int i = 0; i < m; i++) {
Edge& e = egs[i];
if (e.w < in[e.v] && e.u != e.v) {
in[e.v] = e.w;
pre[e.v] = e.u;
}
}
for (int i = 0; i < n; i++) {
if (i!=rt&&in[i] == INF) return -1;
}
int tot = 0;
memset(id, -1, sizeof(id));
memset(vis, -1, sizeof(vis));
in[rt] = 0;
//找环,缩点
for (int i = 0; i < n; i++) {
ret += in[i];
int v = i;
while (vis[v] != i&&id[v] == -1 && v != rt) {
vis[v] = i;
v = pre[v];
}
if (id[v] == -1 && v != rt) {
for (int u = pre[v]; u != v; u = pre[u]) {
id[u] = tot;
}
id[v] = tot++;
}
}
//没有环
if (tot == 0) break;
for (int i = 0; i < n; i++) {
if (id[i] == -1) id[i] = tot++;
}
//更新到环的距离
for (int i = 0; i < m; i++) {
Edge& e = egs[i];
int v = e.v;//这个v要留下来!
e.u = id[e.u],e.v = id[e.v];
if (e.u != e.v) {
e.w -= in[v];
}
}
n = tot;
rt = id[rt];
}
return ret;
}
2.3、增量最小生成树
首先找到一颗最小生成树,之后每加一条边,在形成的环上删除权值最大的边。
2.4、次小生成树
- 法一:删除最小生成树中的一条边,再重新跑一遍最小生成树
- 法二:次小生成树一定可以由最小生成树加一条边再删一条边得到,因此只要枚举不在生成树上的没一条边,形成环之后删除环上的最大边就可以了。
2.5、最小瓶颈路
- 法一:二分加bfs。
- 法二:最小生成树上的路就是最小瓶颈路。
2.6、生成树计数问题
Matrix-tree:
//C[i][j]=无相图的度数矩阵-无相图的邻接矩阵
//Det求n-1阶主子式的行列式
LL Det(int n) {
LL ret = 1;
int f = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
C[i][j] = (C[i][j] % mod + mod) % mod;
}
}
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= n; j++) {
int A = C[i][i], B = C[j][i];
while (B != 0) {
LL t = A / B; A = A%B; swap(A, B);
for (int k = i; k <= n; k++) {
C[i][k] = (C[i][k] - t*C[j][k] % mod + mod) % mod;
}
for (int k = i; k <= n; k++) {
swap(C[i][k], C[j][k]);
}
f = -f;
}
}
ret = ret*C[i][i] % mod;
}
if (f == -1) ret = ((-ret) % mod + mod) % mod;
return ret;
}
3、LCA
3.1、在线倍增
//dep:深度,fa:父亲,anc:祖先
int dep[maxn];
int anc[maxn][maxm];
void dfs(int u,int f,int d) {
dep[u]=d;
anc[u][0]=f;
for(int i=1; i<maxm; i++) {
anc[u][i]=anc[anc[u][i-1]][i-1];
}
for(int p=head[u]; p!=-1; p=egs[p].ne) {
Edge& e=egs[p];
if(e.v==f) continue;
dfs(e.v,u,d+1);
}
}
int Lca(int u,int v) {
if(dep[u]<dep[v]) swap(u,v);
for(int i=maxm-1; i>=0; i--) {
if(dep[anc[u][i]]>=dep[v]) {
u=anc[u][i];
}
}
if(u==v) return u;
for(int i=maxm-1; i>=0; i--) {
if(anc[u][i]!=anc[v][i]) {
u=anc[u][i];
v=anc[v][i];
}
}
return anc[u][0];
}
void init(){
clr(anc[0],0);
}