版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/86708209
文章目录
前言
因为老是懒得打模板的时候老是扣不到自己的标(因为之前的都打得太丑了),所以导致我十分的不爽。便打算开一个模板库。会不断更新的
图论模板
最短路-Floyd
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(dis[i][n]+dis[n][j]<dis[i][j])
dis[i][j]=dis[i][n]+dis[ks][j];
最短路-SPFA
struct edge_node{
int to,next,w;
}a[M];
void addl(int x,int y,int w){
a[++tot].to=y;
a[tot].next=ls[x];
a[tot].w=w;
ls[x]=tot;
}
void spfa(int s)
{
memset(f,0x3f,sizeof(f));
q.push(s);v[s]=1;
f[s]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(f[x]+a[i].w<f[y]){
f[y]=f[x]+a[i].w;
if(!v[y]){
v[y]=1;
q.push(y);
}
}
}
v[x]=false;
}
}
最短路-Dij+堆优化
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=100010,M=200010;
struct node{
int pos,dis;
bool operator<(const node &x)const
{return x.dis<dis;}
};
struct edge_node{
int to,next,w;
}a[M];
priority_queue<node> q;
int tot,ls[N],dis[N],n,m,S;
bool v[N];
void addl(int x,int y,int w)
{
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;
a[tot].w=w;
}
void dij(int s)
{
dis[s]=0;
q.push((node){s,0});
while(!q.empty())
{
node tmp=q.top();q.pop();
int x=tmp.pos;
if(v[x]) continue;v[x]=1;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(dis[y]>dis[x]+a[i].w){
dis[y]=dis[x]+a[i].w;
if(!v[y])
q.push(node{y,dis[y]});
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&S);
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=m;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addl(x,y,w);
}
dij(S);
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
}
}
最小生成树-Kruskal
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=301,M=100010;
struct node{
int x,y,w;
}a[M];
int n,m,fa[N],ans,k;
bool cmp(node x,node y)
{return x.w<y.w;}
int find(int x)
{return fa[x]==x?x:find(fa[x]);}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
for(int i=1;i<=n;i++)
fa[i]=i;
sort(a+1,a+1+m,cmp);
for(int i=1;i<=m;i++){
int Fa=find(a[i].x),Fb=find(a[i].y);
if(Fa!=Fb){
fa[Fb]=Fa;
ans+=a[i].w;
k++;
}
if(k==n-1) break;
}
printf("%d %d",k,ans);
}
最小生成树-Prim+堆优化
这个坑先放着,以后再填
最大匹配-匈牙利算法
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1010;
struct line{
int to,next;
}a[N*N];
int link[N],n,m,ls[N],tot,s,e;
bool cover[N];
void addl(int x,int y)
{
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;
}
bool find(int x)
{
int p=0;
for (int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if (!cover[y])
{
p=link[y];
link[y]=x;
cover[y]=true;
if (!p || find(p)) return true;
link[y]=p;
}
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
for (int i=1;i<=e;i++)
{
int x,y;
scanf("%d%d",&x,&y);
if(x>m||y>m) continue;
addl(x,y);
}
for (int i=1;i<=n;i++)
{
memset(cover,false,sizeof(cover));
if (find(i)) s++;
}
printf("%d",s);
}
tarjan求割点
#include<cstdio>
#include<algorithm>
#define N 20100
#define M 100100
using namespace std;
struct node{
int to,next;
}a[M*2];
int n,m,tot,dfn[N],low[N],ls[N],cnt,z,root;
bool mark[N],v[N];
void addl(int x,int y)
{
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;
}
void tarjan(int x)
{
dfn[x]=low[x]=++cnt;
int flag=0;
for(int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
v[y]=0;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(dfn[x]<=low[y])
{
flag++;
if((x!=root||flag>1)&&!mark[x])
mark[x]=1,z++;
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
if(x==y) continue;
addl(x,y);addl(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) root=i,tarjan(i);
printf("%d\n",z);
for(int i=1;i<=n;i++)
if(mark[i]) printf("%d ",i);
}
tarjan缩点
#include<cstdio>
#include<stack>
#include<queue>
#include<cstring>
#define N 10000
#define M 100000
using namespace std;
stack<int> Stack;
queue<int> q;
struct line{
int to,from,next;
}a[M];
int n,m,x,y,tot,in[N],ls[N],fl[N],cost[N],f[N],maxs,low[N],dfn[N],top,num,gt[N],an[N];
bool ins[N],v[N];
void addl(int x,int y,int tot)
{
a[tot].to=y;
a[tot].from=x;
a[tot].next=ls[x];
ls[x]=tot;
}
void tarjan(int x)
{
ins[x]=true;
dfn[x]=low[x]=++top;
Stack.push(x);
for (int i=ls[x];i;i=a[i].next)
if (!dfn[a[i].to])
{
tarjan(a[i].to);
low[x]=min(low[x],low[a[i].to]);
}
else if (ins[a[i].to])
low[x]=min(low[x],dfn[a[i].to]);
if (low[x]==dfn[x])
{
while (Stack.top()!=x)
{
int y=Stack.top();
fl[y]=x;
an[x]+=cost[y];//计算强联通权值和
Stack.pop();
ins[y]=0;
}
fl[x]=x;
an[x]+=cost[x];//计算强联通权值和
ins[x]=0;
Stack.pop();
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d",&cost[i]);
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
addl(x,y,i);//加边
}
for (int i=1;i<=n;i++)
if (!dfn[i])
tarjan(i);//求强联通
memset(ls,0,sizeof(ls));//去除所有的边的连通(保留值的)
for (int i=1;i<=m;i++)
{
x=a[i].from;y=a[i].to;
if (fl[x]!=fl[y])//不在强联通中
{
tot++;
addl(fl[x],fl[y],tot);//连边
in[fl[y]]++;//统计入度
}
}
}
LCA-树上倍增
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#define N 600001
using namespace std;
struct line{
int to,next,w;
}a[N*5];
int tot,n,m,s,x,y,ls[N],dep[N],f[N][30],dis[N][30],t;
queue<int> q;
inline int readn()
{
int X=0,w=0; char c=0;
while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
return w?-X:X;
}
inline void addl(int x,int y,int w)
{
a[++tot].to=y;
a[tot].next=ls[x];
a[tot].w=w;
ls[x]=tot;
}
inline void bfs(int s)
{
q.push(s);dep[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
for (int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if (dep[y]) continue;
q.push(y);f[y][0]=x;
dep[y]=dep[x]+1;
dis[y][0]=a[i].w;
}
}
t=(int)(log(n)/log(2))+1;
for (int j=1;j<=t;j++)
{
for (int i=1;i<=n;i++)
{
f[i][j]=f[f[i][j-1]][j-1];
dis[i][j]=min(dis[i][j-1],dis[f[i][j-1]][j-1]);
}
}
}
inline int LCA(int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
for (int i=t;i>=0;i--)
if (dep[f[y][i]]>=dep[x]) y=f[y][i];
if (x==y) return x;
for (int i=t;i>=0;i--)
if (f[y][i]!=f[x][i])
{
x=f[x][i];
y=f[y][i];
}
return f[x][0];
}
int main()
{
n=readn();m=readn();s=readn();
for(int i=1;i<n;i++)
{
addl(x=readn(),y=readn(),1);
addl(y,x,1);
}
bfs(s);
for(int i=1;i<=m;i++)
{
printf("%d\n",LCA(readn(),readn()));
}
}
LCA-tarjan+并查集优化
#include<cstdio>
#include<iostream>
using namespace std;
struct line{
int next,to;
}a[20001];
int father[10001],n,m,q,p,v[10001],ans,tot,ls[10001],t,x,y,in[10001];
bool ok;
void addl(int x,int y)//加边
{
a[++tot].to=y;
a[tot].next=ls[x];
ls[x]=tot;
}
int find(int x)//并查集优化
{
return x==father[x]?x:find(father[x]);
}
void tarjan(int x)
{
v[x]=1;
for (int i=ls[x];i;i=a[i].next)//子节点
{
int y=a[i].to;
if (v[y]) continue;
tarjan(y);//tarjan一遍
father[y]=x;//记录祖先
}
if (ok) return;//标记已找到
if (v[q]==2 && x==p)
{
printf("%d\n",find(q));//输出
ok=true;
return;
}
if (v[p]==2 && x==q)///输出
{
printf("%d\n",find(p));
ok=true;
return;
}
v[x]=2;
}
int main()
{
scanf("%d",&t);
for (;t;t--)
{
scanf("%d",&n);
tot=0;ok=0;
for (int i=1;i<=n;i++){
ls[i]=0;father[i]=i;v[i]=0;
in[i]=0;
}
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
in[y]++;
addl(x,y);addl(y,x);
}
scanf("%d%d",&q,&p);
for (int i=1;i<=n;i++)//寻找根
if (in[i]==0) tarjan(i);
//printf("%d\n",ans);
}
}
网络流-最大流dinic
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N=10010,M=100010,inf=2147483647/3;
struct node{
int to,next,w;
}a[M*2];
int tot=1,n,s,t,m,ans;
int dep[N],ls[N];
queue<int> q;
void addl(int x,int y,int w)
{
a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
while(!q.empty()) q.pop();
q.push(s);dep[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if(!dep[y]&&a[i].w){
dep[y]=dep[x]+1;
if(y==t) return true;
q.push(y);
}
}
}
return false;
}
int dinic(int x,int flow)
{
int rest=0,k;
if(x==t) return flow;
for(int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if(dep[x]+1==dep[y]&&a[i].w)
{
rest+=(k=dinic(y,min(a[i].w,flow-rest)));
a[i].w-=k;a[i^1].w+=k;
if(rest==flow) return flow;
}
}
if(!rest) dep[x]=0;
return rest;
}
void netflow()
{
while(bfs())
ans+=dinic(s,inf);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addl(x,y,w);
}
netflow();
printf("%d",ans);
}
网络流-最小费用最大流
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=5010,M=50010,inf=2147483647/3;
struct node{
int to,w,c,next;
}a[M*2];
queue<int>q;
int f[N],mf[N],ls[N],pre[N];
int n,s,e,tot,m,anscost,ansflow;
bool v[N];
void addl(int x,int y,int w,int c)
{
a[++tot].w=w;a[tot].to=y;a[tot].c=c;a[tot].next=ls[x];ls[x]=tot;
a[++tot].w=0;a[tot].to=x;a[tot].c=-c;a[tot].next=ls[y];ls[y]=tot;
}
bool spfa()
{
memset(f,0x3f,sizeof(f));
memset(v,0,sizeof(v));
memset(mf,0,sizeof(mf));
q.push(s);f[s]=0;v[s]=1;mf[s]=inf;
while(!q.empty()){
int x=q.front();q.pop();v[x]=0;
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(f[x]+a[i].c<f[y]&&a[i].w){
f[y]=f[x]+a[i].c;
mf[y]=min(mf[x],a[i].w);
pre[y]=i;
if(!v[y]){
v[y]=true;
q.push(y);
}
}
}
}
return f[e]<=2147483647/3;
}
int updata()
{
int x=e;
while(x!=s){
a[pre[x]].w-=mf[e];
a[pre[x]^1].w+=mf[e];
x=a[pre[x]^1].to;
}
anscost+=f[e]*mf[e];
ansflow+=mf[e];
}
void netflow()
{
while(spfa())
updata();
}
int main()
{
tot=1;
scanf("%d%d%d%d",&n,&m,&s,&e);
for(int i=1;i<=m;i++){
int x,y,w,c;
scanf("%d%d%d%d",&x,&y,&w,&c);
addl(x,y,w,c);
}
netflow();
printf("%d %d",ansflow,anscost);
}
负环
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=2100,M=3100;
struct node{
int to,next,w;
}a[M*2];
queue<int> q;
int n,m,tot,ls[N],f[N],cnt[N],T;
bool v[N];
void addl(int x,int y,int w)
{
a[++tot].to=y;
a[tot].next=ls[x];
a[tot].w=w;
ls[x]=tot;
}
bool spfa()
{
memset(f,0x3f,sizeof(f));
memset(cnt,0,sizeof(cnt));
q.push(1);cnt[1]=1;
f[1]=0;v[1]=1;
while(!q.empty()){
int x=q.front();v[x]=0;
q.pop();
for(int i=ls[x];i;i=a[i].next){
int y=a[i].to;
if(f[x]+a[i].w<f[y]){
f[y]=f[x]+a[i].w;
cnt[y]=cnt[x]+1;
if(cnt[y]>=n&&a[i].w<0)
return true;
if(!v[y]){
v[y]=1;
q.push(y);
}
}
}
}
return false;
}
int main()
{
scanf("%d",&T);
while(T--)
{
memset(ls,0,sizeof(ls));
tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
addl(x,y,w);
if(w>=0) addl(y,x,w);
}
if(spfa()) printf("YE5");
else printf("N0");
putchar('\n');
}
}