亿些模板【图论】

版权声明:原创,未经作者允许禁止转载 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');
    }
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/86708209
今日推荐