ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【模板】图论

2022-08-28 22:32:39  阅读:133  来源: 互联网

标签:nxt 图论 return int flow co 模板 ver


最小环

Floyd 求最小环+输路径

模板指路

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

int a[105][105],d[105][105],pa[105][105],ans[105];
int mi=1e9,co;

void get_pa(int x,int y){
	if(!pa[x][y])	return;
	get_pa(x,pa[x][y]);
	ans[++co]=pa[x][y];
	get_pa(pa[x][y],y);
}

signed main(){
	
	int n,m;cin>>n>>m;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)	a[i][j]=d[i][j]=1e9;
	for(int i=1;i<=m;++i){
		int x,y,z;cin>>x>>y>>z;
		a[x][y]=a[y][x]=d[x][y]=d[y][x]=min(z,d[x][y]);
	}
	
	for(int k=1;k<=n;++k){
		for(int i=1;i<k;++i)
			for(int j=i+1;j<k;++j)
				if(d[i][j]+a[i][k]+a[k][j]<mi){
					mi=d[i][j]+a[i][k]+a[k][j];
					co=0;
					get_pa(i,j),ans[++co]=j,ans[++co]=k,ans[++co]=i;
				}
		for(int i=1;i<=n;++i)
			for(int j=1;j<=n;++j)
				if(d[i][j]>d[i][k]+d[k][j]){
					d[i][j]=d[i][k]+d[k][j];
					pa[i][j]=k;
				}
	}
	if(mi==1e9)	cout<<"No solution.";
	else	for(int i=1;i<=co;++i)	cout<<ans[i]<<" ";
	
	return 0;
}

LCA

倍增求LCA

模板指路

点击查看代码
const int N=5e5+5;
int fa[N][30],d[N];
int s=1;
vector<int> ed[N];

void bfs(){
    queue<int> q;
    q.push(s);d[0]=-1e9;
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=0;i<(int)ed[x].size();++i){
            int y=ed[x][i];
            if(y==s || d[y])    continue;
            d[y]=d[x]+1;q.push(y);
            fa[y][0]=x;
            for(int j=1;j<=20;++j)
                fa[y][j]=fa[fa[y][j-1]][j-1];
        }
    }
}
int lca(int x,int y){
    if(d[y]>d[x])   swap(x,y);
    for(int i=20;i>=0;--i)
        if(d[fa[x][i]]>=d[y])   x=fa[x][i];
    if(x==y)    return x;
    for(int i=20;i>=0;--i)
        if(fa[x][i]!=fa[y][i])
            x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

Tarjan

模板指路

点击查看代码
#include<bits/stdc++.h>
using namespace std;
//桥一定要去重边!!!
const int N=2e3+5,M=2e6+5;
int dfn[N],low[N],cnt;
int h[N],nxt[M],ver[M],st[M],co;
bool a[N][N];
int n,m;
set<pair<int,int> > s;

void add(int x,int y){
	nxt[++co]=h[x],h[x]=co,ver[co]=y,st[co]=x;
}

int tarjan(int x,int fa){
	dfn[x]=++cnt,low[x]=cnt;

	for(int i=h[x];i;i=nxt[i]){
		int y=ver[i];
		if(y==fa)	continue;
		if(dfn[y])	low[x]=min(low[x],low[y]);
		else	low[x]=min(low[x],tarjan(y,x));

		if(low[y]>dfn[x])	s.insert(make_pair(min(st[i],ver[i]),max(st[i],ver[i])));
	}
	return low[x];
}

int main(){

	int n,m;cin>>n>>m;
	for(int i=1;i<=m;++i){
		int x,y;cin>>x>>y;
		if(a[x][y]) continue;
		add(x,y),add(y,x),a[x][y]=a[y][x]=1;
	}

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

	cout<<s.size()<<endl;
	for(auto it:s)
		cout<<it.first<<" "<<it.second<<endl;

	return 0;
}

割点

模板指路

点击查看代码
#include<bits/stdc++.h>
using namespace std;
//割点不用去重边!!!
const int N=2e4+5,M=1e5+5;
vector<int> ed[N];
int dfn[N],low[N],cnt;
set<int> s;

int tarjan(int x,int fa){
	low[x]=dfn[x]=++cnt;
	int co=0;
	for(int i=0;i<ed[x].size();++i){
		int y=ed[x][i];
		if(y==fa)	continue;
		if(!dfn[y]){
			low[x]=min(low[x],tarjan(y,x)),++co;
			if(fa && low[y]>=dfn[x])	s.insert(x);
		}
		else	low[x]=min(low[x],dfn[y]);
	}
	if(!fa && co>1)	s.insert(x);
	return low[x];
}

int main(){

	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;++i){
		int x,y;cin>>x>>y;
		ed[x].push_back(y);
		ed[y].push_back(x);
	}

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

	cout<<s.size()<<endl;
	for(auto it:s)	cout<<it<<" ";

	return 0;
}

缩点、Tarjan 求强联通分量

模板指路

点击查看代码
//Luogu P3387 【模板】缩点
#include<bits/stdc++.h>
using namespace std;

const int N=1e4+5,M=1e5+5;
vector<int> ed[N],e[N];
int dfn[N],low[N],st[N],top,cnt;
bool vi[N];
int a[N],ans;
int w[N],co,d[N],f[N],dp[N];
int n,m;
struct edge{
	int x,y;
}edg[M];

int tarjan(int x){
	dfn[x]=low[x]=++cnt;
	st[++top]=x;
	vi[x]=1;
	for(int i=0;i<ed[x].size();++i){
		if(vi[ed[x][i]])	low[x]=min(low[x],low[ed[x][i]]);
		if(!dfn[ed[x][i]])	low[x]=min(low[x],tarjan(ed[x][i]));
	}
	if(dfn[x]==low[x]){
		int sum=a[x];
		while(top && st[top]!=x)
			f[st[top]]=x,sum+=a[st[top]],vi[st[top]]=0,--top;
		--top,vi[x]=0,f[x]=x;
		w[x]=sum;
	}
	return low[x];
}

void topo(){
	queue<int> q;
	for(int i=1;i<=n;++i)
		if(f[i]==i && !d[i])	q.push(i),dp[i]=w[i];
	while(q.size()){
		int x=q.front();q.pop();
		ans=max(ans,dp[x]);
		for(int i=0;i<e[x].size();++i){
			int y=e[x][i];
			dp[y]=max(dp[y],dp[x]+w[y]);
			d[y]--;
			if(!d[y])	q.push(y);
		}
	}
}

int main(){
	
	cin>>n>>m;
	for(int i=1;i<=n;++i)	cin>>a[i];
	for(int i=1;i<=m;++i){
		cin>>edg[i].x>>edg[i].y;
		ed[edg[i].x].push_back(edg[i].y);
	}
	
	for(int i=1;i<=n;++i)
		if(!dfn[i])	tarjan(i);
	
	for(int i=1;i<=m;++i)
		if(f[edg[i].x]!=f[edg[i].y]){
			d[f[edg[i].y]]++;
			e[f[edg[i].x]].push_back(f[edg[i].y]);
		}
	
	topo();
	
	cout<<ans;
	
	return 0;
}

基环树

拓扑排序找环(无向图)

模板
void topo(int x){
    queue<int> q;
    for(int i=1;i<=n;++i)
        if(d[i]==1)	q.push(cal[x][i]);
    while(q.size()){
        int y=q.front();q.pop();
        for(int i=0;i<ed[y].size();++i){
            int z=ed[y][i];
            if(d[z]<=1)	continue;
            --d[z];
            if(d[z]==1)	q.push(z);
        }
    }

    for(int i=1;i<=n;++i)
		if(d[i]>1)	++cnt;
}

二分图

二分图最大匹配(匈牙利算法)

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=505,M=5e4+5;
int h[N],nxt[M],en[M],co;
bool v[N];
int match[N];

void add(int a,int b){
	nxt[++co]=h[a],en[co]=b,h[a]=co;
}

bool dfs(int x){
	for(int i=h[x];i;i=nxt[i])
		if(!v[en[i]]){
			v[en[i]]=1;
			if(!match[en[i]] || dfs(match[en[i]])){
				match[en[i]]=x;
				return 1;
			}
		}
	return 0;
}

int main(){
	
	int n,m,e;
	cin>>n>>m>>e;
	for(int i=1;i<=e;i++){
		int a,b;
		cin>>a>>b;
		add(a,b);
	}
	
	int ans=0;
	for(int i=1;i<=n;i++){
		memset(v,0,sizeof v);
		if(dfs(i))	ans++;
	}
	
	cout<<ans;
	
	return 0;
}

网络流

最大流、最小费用最大流、最小割

Dinic(最大网络流=最小割)

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5,M=2e3+5,INF=0x3f3f3f3f;
int nxt[N],h[M],w[N],ver[N],co=1;
int n,m,s,t;
int d[M],no[M];

inline int read(){
	int sum=0,f=1;char a=getchar();
	while(a<'0' || a>'9'){if(a=='-') 	f=-1;a=getchar();}
	while(a>='0' && a<='9') 	sum=sum*10+a-'0',a=getchar();
	return sum*f;
}


void add(int x,int y,int z){
	nxt[++co]=h[x],h[x]=co,ver[co]=y,w[co]=z;
	nxt[++co]=h[y],h[y]=co,ver[co]=x,w[co]=0;
}

bool bfs(){
	memset(d,0,sizeof d);
	queue<int> q;
	q.push(s);
	d[s]=1,no[s]=h[s];
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=h[x];i;i=nxt[i]){
			int y=ver[i];
			if(!d[y] && w[i]){
				d[y]=d[x]+1;
				no[y]=h[y];
				q.push(y);
				if(y==t)	return 1;
			}
		}
	}
	return 0;
}

int dfs(int x,int flow){
	if(x==t)	return flow;
	int rest=flow,k,i;
	for(i=no[x];i && rest;i=nxt[i]){
		int y=ver[i];
		if(d[y]==d[x]+1 && w[i]){
			k=dfs(y,min(rest,w[i]));
			if(!k)	d[y]=0;
			w[i]-=k;
			w[i^1]+=k;
			rest-=k;
		}
	}
	no[x]=i;
	return flow-rest;
}

int main(){
	
	n=read(),m=read();
	s=1,t=n;
	for(int i=1;i<=m;++i){
		int x=read(),y=read(),z=read();
		add(x,y,z);
	}
	
	int ans=0,flow=0;
	while(bfs())
		while(flow=dfs(1,INF))
		ans+=flow;
	
	cout<<ans<<endl;
	
	return 0;
}

EK(最小费用流)

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=5e3+5,M=1e5+5,INF=0x3f3f3f3f;
int nxt[M],h[N],ver[M],w[M],fl[M];
int n,m,s,t,co=1;//co=1!!!!!!!
bool vi[N];
int pre[N],dis[N];

inline int read(){
	int sum=0,f=1;char a=getchar();
	while(a<'0' || a>'9'){if(a=='-') 	f=-1;a=getchar();}
	while(a>='0' && a<='9') 	sum=sum*10+a-'0',a=getchar();
	return sum*f;
}

void add(int x,int y,int z,int d){
	nxt[++co]=h[x],h[x]=co,ver[co]=y,w[co]=z,fl[co]=d;
	nxt[++co]=h[y],h[y]=co,ver[co]=x,w[co]=-z,fl[co]=0;
}

bool spfa(){
	memset(dis,0x3f,sizeof dis);
	memset(vi,0,sizeof vi);
	queue<int> q;
	vi[s]=1,dis[s]=0;
	q.push(s);
	while(q.size()){
		int x=q.front();q.pop();
		vi[x]=0;
		for(int i=h[x];i;i=nxt[i]){
			int y=ver[i];
			if(dis[y]>dis[x]+w[i] && fl[i]){
				pre[y]=i;
				dis[y]=dis[x]+w[i];
				if(vi[y])	continue;
				vi[y]=1;
				q.push(y);
			}
		}
	}
	if(dis[t]==INF)	return 0;
	return 1;
}

int main(){
	
	n=read(),m=read(),s=read(),t=read();
	for(int i=1;i<=m;++i){
		int x,y,z,d;
		x=read(),y=read(),d=read(),z=read();
		add(x,y,z,d);
	}
	
	int flow=0,ans=0;
	while(spfa()){
		int p,mi=INF;
		for(int i=t;i!=s;i=ver[p^1]){
			p=pre[i];
			mi=min(mi,fl[p]);
		}
		for(int i=t;i!=s;i=ver[p^1]){
			p=pre[i];
			fl[p]-=mi;
			fl[p^1]+=mi;
			ans+=w[p]*mi;
		}
		flow+=mi;
	}
	
	cout<<flow<<" "<<ans;
	
	return 0;
}

上下界网络流

无汇源上下界可行流

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=5e4+5,INF=0x3f3f3f3f;
int h[N],nxt[N],ver[N],w[N],co=1;
int in[N],out[N];
int c[N],D[N];
int s,t,n,m;
int d[N],no[N];

void add(int x,int y,int z){
	nxt[++co]=h[x],h[x]=co,ver[co]=y,w[co]=z;
	nxt[++co]=h[y],h[y]=co,ver[co]=x,w[co]=0;
}

bool bfs(){
	memset(d,0,sizeof d);
	queue<int> q;
	q.push(s);
	d[s]=1,no[s]=h[s];
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=h[x];i;i=nxt[i]){
			int y=ver[i];
			if(!d[y] && w[i]){
				d[y]=d[x]+1;
				no[y]=h[y];
				q.push(y);
				if(y==t)	return 1;
			}
		}
	}
	return 0;
}

int dfs(int x,int flow){
	if(x==t)	return flow;
	int rest=flow,k,i;
	for(i=no[x];i && rest;i=nxt[i]){
		int y=ver[i];
		if(d[y]==d[x]+1 && w[i]){
			k=dfs(y,min(rest,w[i]));
			if(!k)	d[y]=0;
			w[i]-=k;
			w[i^1]+=k;
			rest-=k;
		}
	}
	no[x]=i;
	return flow-rest;
}

int main(){
	
	int a,b;
	cin>>n>>m;
	s=n+1,t=s+1;
	for(int i=1;i<=m;++i){
		cin>>a>>b>>c[i]>>D[i];
		add(a,b,D[i]-c[i]);
		in[b]+=c[i],out[a]+=c[i];
	}
	
	int sum=0;
	for(int i=1;i<=n;++i){
		if(in[i]>out[i])	add(s,i,in[i]-out[i]),sum+=in[i]-out[i];
		if(out[i]>in[i])	add(i,t,out[i]-in[i]);
	}
	
	int ans=0,flow=0;
	while(bfs()){
		while(flow=dfs(s,INF))	ans+=flow;
	}
	if(ans!=sum){
		cout<<"NO";
		return 0;
	}
	
	cout<<"YES"<<endl;
	for(int i=2;i<=m*2;i+=2)
		cout<<D[i/2]-w[i]<<endl;
	
	return 0;
}

有汇源有上下界最小流

点击查看代码
#include<bits/stdc++.h>
using namespace std;

const int N=1e5+5,M=2e3+5,INF=0x3f3f3f3f;
int nxt[N],h[M],w[N],ver[N],co=1;
int n,m,s,t;
int in[N],out[N];
int d[M],no[M];

void add(int x,int y,int z){
	nxt[++co]=h[x],h[x]=co,ver[co]=y,w[co]=z;
	nxt[++co]=h[y],h[y]=co,ver[co]=x,w[co]=0;
}

bool bfs(){
	memset(d,0,sizeof d);
	queue<int> q;
	q.push(s);
	d[s]=1,no[s]=h[s];
	while(q.size()){
		int x=q.front();q.pop();
		for(int i=h[x];i;i=nxt[i]){
			int y=ver[i];
			if(!d[y] && w[i]){
				d[y]=d[x]+1;
				no[y]=h[y];
				q.push(y);
				if(y==t)	return 1;
			}
		}
	}
	return 0;
}

int dfs(int x,int flow){
	if(x==t)	return flow;
	int rest=flow,k,i;
	for(i=no[x];i && rest;i=nxt[i]){
		int y=ver[i];
		if(d[y]==d[x]+1 && w[i]){
			k=dfs(y,min(rest,w[i]));
			if(!k)	d[y]=0;
			w[i]-=k;
			w[i^1]+=k;
			rest-=k;
		}
	}
	no[x]=i;
	return flow-rest;
}

int dinic(){
	int ans=0,flow=0;
	while(bfs()){
		while(flow=dfs(s,INF))	ans+=flow;
	}
	return ans;
}

int main(){
	
	int a,b,c,d;
	cin>>n;
	s=n+1,t=s+1;
	while(cin>>a>>b>>c>>d){
		add(a,b,d-c);
		in[b]+=c,out[a]+=c;
	}
	for(int i=1;i<=n;++i){
		if(in[i]>out[i])	add(s,i,in[i]-out[i]);
		if(out[i]>in[i])	add(i,t,out[i]-in[i]);
	}
	add(n,1,INF);
	
	dinic();
	int t1=INF-w[co^1];
	s=n,t=1,w[co]=0,w[co^1]=0;
	int t2=dinic();
	
	cout<<t1-t2;
	
	return 0;
}

标签:nxt,图论,return,int,flow,co,模板,ver
来源: https://www.cnblogs.com/yolanda-yxr/p/16634273.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有