图论模板
前言
图论算法千千万,这只蒟蒻团团转。
以下程序大都在洛谷等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;
}
持续更新中……

浙公网安备 33010602011771号