图论模板

前言

图论算法千千万,这只蒟蒻团团转。
以下程序大都在洛谷等OJ提交过,保证正确率95%以上(请大佬多多Hack)
程序主要来源:《算法竞赛进阶指南》李煜东著

单源最短路

Dijkstra+Heap

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

const int N=100010,M=1000010;

int head[N],ver[M],edge[M],Next[M],d[N];
bool v[N];
int n,m,s,tot;

priority_queue<pair<int,int> > q;

void add(int x,int y,int z){
	ver[++tot]=y;
	edge[tot]=z;
	Next[tot]=head[x];
	head[x]=tot;
}

void dijkstra(int s){
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));

	d[s]=0;

	q.push(make_pair(0,s));

	while(q.size()){
		int x=q.top().second;
		q.pop();

		if(v[x])
			continue;

		v[x]=1;

		for(int i=head[x];i;i=Next[i]){
			int y=ver[i],z=edge[i];

			if(d[y]>d[x]+z){
				d[y]=d[x]+z;
				q.push(make_pair(-d[y],y));
			}
		}
	}
}

int main(){
	cin>>n>>m>>s;

	for(int i=1;i<=m;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}

	dijkstra(s);

	for(int i=1;i<=n;i++)
		printf("%d ",d[i]);

	puts("");
	return 0;
}

SPFA(没有负权边禁用)

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

const int N=100010,M=1000010;

int head[N],ver[M],edge[M],Next[M],d[N];
int n,m,s,tot;
queue<int> q;
bool v[N];

void add(int x,int y,int z){
	ver[++tot]=y;
	edge[tot]=z;
	Next[tot]=head[x];
	head[x]=tot;
}

void spfa(int s){
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));

	d[s]=0;
	v[s]=1;
	q.push(s);

	while(q.size()){
		int x=q.front();
		q.pop();
		v[x]=0;

		for(int i=head[x];i;i=Next[i]){
			int y=ver[i],z=edge[i];

			if(d[y]>d[x]+z){
				d[y]=d[x]+z;
				if(!v[y])
					q.push(y),v[y]=1;
			}
		}
	}
}

int main(){
	cin>>n>>m>>s;

	for(int i=1;i<=m;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
	}

	spfa(s);
	
	for(int i=1;i<=n;i++)
		printf("%d ",d[i]);

	puts("");
	return 0;
}

全源最短路

Floyd

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

int d[310][310],n,m;

int main(){
	cin>>n>>m;

	memset(d,0x3f,sizeof(d));

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

	for(int i=1;i<=m;i++){
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		d[x][y]=min(d[x][y],z);
	}

	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				d[i][j]=min(d[i][j],d[i][k]+d[k][j]);

	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++)
			printf("%d ",d[i][j]);

		puts("");
	}

	return 0;
}

最小生成树

Kruskal

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

struct rec{
	int x,y,z;
}edge[500010];

int fa[100010],n,m,ans;

bool operator <(rec a,rec b){
	return a.z<b.z;
}

int get(int x){
	if(x==fa[x])
		return x;

	return fa[x]=get(fa[x]);
}

int main(){
	cin>>n>>m;

	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);

	sort(edge+1,edge+m+1);

	for(int i=1;i<=n;i++)
		fa[i]=i;

	for(int i=1;i<=m;i++){
		int x=get(edge[i].x);
		int y=get(edge[i].y);

		if(x==y)
			continue;

		fa[x]=y;
		ans+=edge[i].z;
	}

	cout<<ans<<"\n";
	return 0;
}

Prim(主要用于稠密图)

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

int a[5010][5010],d[5010],n,m,ans;
bool v[5010];

void prim(){
	memset(d,0x3f,sizeof(d));
	memset(v,0,sizeof(v));

	d[1]=0;

	for(int i=1;i<n;i++){
		int x=0;

		for(int j=1;j<=n;j++)
			if(!v[j] && (x==0 || d[j]<d[x]))
				x=j;

		v[x]=1;
		
		for(int y=1;y<=n;y++)
			if(!v[y])
				d[y]=min(d[y],a[x][y]);
	}
}

int main(){
	cin>>n>>m;

	memset(a,0x3f,sizeof(a));

	for(int i=1;i<=n;i++)
		a[i][i]=0;

	for(int i=1;i<=m;i++){
		int x,y,z;
		scanf("%d %d %d",&x,&y,&z);
		a[y][x]=a[x][y]=min(a[x][y],z);
	}

	prim();

	for(int i=2;i<=n;i++)
		ans+=d[i];

	cout<<ans<<"\n";
	return 0;
}

强连通分量

Tarjan

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

const int N=100010,M=1000010;

int ver[M],Next[M],head[N],dfn[N],low[N];
int vc[M],nc[M],hc[N];
int st[N],ins[N],c[N];
vector<int> scc[N];
int n,m,tot,tc,num,top,cnt;

void add(int x,int y){
	ver[++tot]=y;
	Next[tot]=head[x];
	head[x]=tot;
}

void tarjan(int x){
	dfn[x]=low[x]=++num;
	st[++top]=x,ins[x]=1;

	for(int i=head[x];i;i=Next[i])
		if(!dfn[ver[i]]){
			tarjan(ver[i]);
			low[x]=min(low[x],low[ver[i]]);
		}
		else if(ins[ver[i]])
			low[x]=min(low[x],dfn[ver[i]]);

	if(dfn[x]==low[x]){
		cnt++;
		int y;

		do{
			y=st[top--];
			ins[y]=0;
			c[y]=cnt;
			scc[cnt].push_back(y);
			cout<<y<<" ";
		}while(x!=y);

		puts("");
	}
}

int main(){
	cin>>n>>m;

	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d %d",&x,&y);
		add(x,y);
	}

	for(int i=1;i<=n;i++)
		if(!dfn[i])
			tarjan(i);

	return 0;
}

二分图最大匹配

匈牙利算法

#define _CRT_SECURE_NO_WARNINGS
#include <bits/stdc++.h>
using namespace std;

int n1,n2,m,ans;
int result[1010];
bool state[1010];
bool dat[1010][1010];

void init(){
	int t1,t2;

	memset(dat,0,sizeof(dat));
	memset(result,0,sizeof(result));
	
	ans=0;
	scanf("%d%d%d",&n1,&n2,&m);

	for(int i=1;i<=m;i++){
		scanf("%d%d",&t1,&t2);
		dat[t1][t2]=true;
	}
}

bool find(int a){
	for(int i=1;i<=n2;i++){
		if(dat[a][i]==1&&!state[i]){
			state[i]=true;

			if(result[i]==0||find(result[i])){
				result[i]=a;
				return true;
			}
		}
	}

	return false;
}

int main(){
	init();

	for(int i=1;i<=n1;i++){
		memset(state,0,sizeof(state));

		if(find(i))
			ans++;
	}

	printf("%d\n",ans);

	return 0;
}

LCA

树上倍增

#include <bits/stdc++.h>
using namespace std;

const int SIZE=500010;

int f[SIZE][20],d[SIZE],dist[SIZE];
int ver[2*SIZE],Next[2*SIZE],edge[2*SIZE],head[SIZE];
int T,n,m,tot,t;
queue<int> q;

void add(int x,int y,int z){
    ver[++tot]=y;
    edge[tot]=z;
    Next[tot]=head[x];
    head[x]=tot;
}

void bfs(){
    q.push(1);
    d[1]=1;
    
    while(q.size()){
        int x=q.front();
        q.pop();
        
        for(int i=head[x];i;i=Next[i]){
            int y=ver[i];
            
            if(d[y])
                continue;
                
            d[y]=d[x]+1;
            dist[y]=dist[x]+edge[i];
            f[y][0]=x;
            
            for(int j=1;j<=t;j++)
                f[y][j]=f[f[y][j-1]][j-1];
                
            q.push(y);
        }
    }
}

int lca(int x,int y){
    if(d[x]>d[y])
        swap(x,y);
        
    for(int i=t;i>=0;i--)
        if(d[f[y][i]]>=d[x])
            y=f[y][i];
            
    if(x==y)
        return x;
        
    for(int i=t;i>=0;i--)
        if(f[x][i]!=f[y][i])
            x=f[x][i],y=f[y][i];
            
    return f[x][0];
}

int main(){
    cin>>T;
    
    while(T--){
        cin>>n>>m;
        
        t=(int)(log(n)/log(2))+1;
        
        for(int i=1;i<=n;i++)
            head[i]=d[i]=0;
            
        tot=0;
        
        for(int i=1;i<n;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        
        bfs();
        
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",dist[x]+dist[y]-2*dist[lca(x,y)]);
        }
    }
    
    return 0;
}

Tarjan

#include <bits/stdc++.h>
using namespace std;

const int SIZE=500010;
int ver[2*SIZE],Next[2*SIZE],edge[2*SIZE],head[SIZE];
int fa[SIZE],d[SIZE],v[SIZE],lca[SIZE],ans[SIZE];
vector<int> query[SIZE],query_id[SIZE];
int T,n,m,tot,t;

void add(int x,int y,int z){
    ver[++tot]=y;
    edge[tot]=z;
    Next[tot]=head[x];
    head[x]=tot;
}

void add_query(int x,int y,int id){
    query[x].push_back(y);
    query_id[x].push_back(id);
    query[y].push_back(x);
    query_id[y].push_back(id);
}

int get(int x){
    if(x==fa[x])
        return x;
        
    return fa[x]=get(fa[x]);
}

void tarjan(int x){
    v[x]=1;
    
    for(int i=head[x];i;i=Next[i]){
        int y=ver[i];
        
        if(v[y])
            continue;
            
        d[y]=d[x]+edge[i];
        
        tarjan(y);
        
        fa[y]=x;
    }
    
    for(int i=0;i<query[x].size();i++){
        int y=query[x][i],id=query_id[x][i];
        
        if(v[y]==2){
            int lca=get(y);
            ans[id]=min(ans[id],d[x]+d[y]-2*d[lca]);
        }
    }
    
    v[x]=2;
}

int main(){
    cin>>T;
    
    while(T--){
        cin>>n>>m;
        
        for(int i=1;i<=n;i++){
            head[i]=0;
            fa[i]=i;
            v[i]=0;
            
            query[i].clear();
            query_id[i].clear();
        }
        
        tot=0;
        
        for(int i=1;i<n;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        
        for(int i=1;i<=m;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            
            if(x==y)
                ans[i]=0;
            else{
                add_query(x,y,i);
                ans[i]=1<<30;
            }
        }
        
        tarjan(1);
        
        for(int i=1;i<=m;i++)
            printf("%d\n",ans[i]);
    }
    
    return 0;
}

持续更新中……

posted @ 2021-03-06 18:16  赵一铭  阅读(96)  评论(0)    收藏  举报