【模板】图论
分类:
IT文章
•
2025-01-21 08:49:01
最小生成树:http://www.cnblogs.com/cangT-Tlan/p/7794372.html
次小生成树:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct nond{
int x,y,z;
}edge[400000];
int T,N,M,x,y,z,fa[200000],num,ans[200000];
int tot,bns,k,answer=0x7f7f7f7f;
int cmp(nond aa,nond bb){
return aa.z<bb.z;
}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main(){
freopen("mst2.in","r",stdin);
freopen("mst2.out","w",stdout);
cin>>N>>M;
for(int i=1;i<=M;i++){
cin>>x>>y>>z;
edge[i].x=x;
edge[i].y=y;
edge[i].z=z;
}
sort(edge+1,edge+1+M,cmp);
for(int i=1;i<=N;i++) fa[i]=i;
for(int i=1;i<=M;i++){
int dx=find(edge[i].x);
int dy=find(edge[i].y);
if(dx!=dy){
fa[dx]=dy;
tot++;
ans[tot]=i;
bns+=edge[i].z;
}
if(tot==N-1) break;
}
for(int i=1;i<=tot;i++){
k=0;num=0;
for(int j=1;j<=N;j++) fa[j]=j;
sort(edge+1,edge+1+M,cmp);
for(int j=1;j<=M;j++){
if(j==ans[i]) continue;
int dx=find(edge[j].x);
int dy=find(edge[j].y);
if(dx!=dy){
fa[dx]=dy;
num++;
k+=edge[j].z;
}
if(num==N-1) break;
}
if(num==N-1&&k!=bns) answer=min(k,answer);
}
cout<<answer;
}
次小生成树
最短路:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<deque>
#define MAXN 500010
using namespace std;
deque<int>que;
int n,m,s,vis[MAXN],num[MAXN],dis[MAXN];
int tot,to[MAXN],from[MAXN],net[MAXN],cap[MAXN];
void add(int u,int v,int w){
to[++tot]=v;net[tot]=from[u];cap[tot]=w;from[u]=tot;
}
bool spfa(int s){
for(int i=1;i<=n;i++) dis[i]=2147483647;
que.push_back(s);
vis[s]=1;num[s]++;dis[s]=0;
while(!que.empty()){
int now=que.front();
que.pop_front();
vis[now]=0;
for(int i=from[now];i;i=net[i])
if(dis[to[i]]>dis[now]+cap[i]){
dis[to[i]]=dis[now]+cap[i];
if(!vis[to[i]]){
if(dis[to[i]]>dis[que.front()])
que.push_back(to[i]);
else
que.push_front(to[i]);
vis[to[i]]=1;
num[to[i]]++;
if(num[to[i]]>n)
return false;
}
}
}
return true;
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
if(spfa(s))
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
spfa 最短路
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define MAXN 500010
using namespace std;
struct nond{
int number,dis;
bool operator < (nond b) const{
return dis>b.dis;
}
};
int n,m,s,dis[MAXN];
int tot,to[MAXN],net[MAXN],from[MAXN],cap[MAXN];
void add(int u,int v,int w){
to[++tot]=v;net[tot]=from[u];cap[tot]=w;from[u]=tot;
}
void dijkstra(int x){
priority_queue<nond>que;
for(int i=1;i<=n;i++) dis[i]=2147483647;
dis[x]=0;
que.push((nond){x,0});
while(!que.empty()){
nond now=que.top();
que.pop();
if(dis[now.number]!=now.dis) continue;
for(int i=from[now.number];i;i=net[i])
if(dis[to[i]]>dis[now.number]+cap[i]){
dis[to[i]]=dis[now.number]+cap[i];
que.push((nond){to[i],dis[to[i]]});
}
}
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
dijkstra(s);
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define MAXN 500010
using namespace std;
struct nond{
int number,dis;
bool operator < (nond b) const{
return dis>b.dis;
}
};
int n,m,s,dis[MAXN];
int tot,to[MAXN],net[MAXN],from[MAXN],cap[MAXN];
void add(int u,int v,int w){
to[++tot]=v;net[tot]=from[u];cap[tot]=w;from[u]=tot;
}
void dijkstra(int x){
priority_queue<nond>que;
for(int i=1;i<=n;i++) dis[i]=2147483647;
dis[x]=0;
que.push((nond){x,0});
while(!que.empty()){
nond now=que.top();
que.pop();
if(dis[now.number]!=now.dis) continue;
for(int i=from[now.number];i;i=net[i])
if(dis[to[i]]>dis[now.number]+cap[i]){
dis[to[i]]=dis[now.number]+cap[i];
que.push((nond){to[i],dis[to[i]]});
}
}
}
int main(){
cin>>n>>m>>s;
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
}
dijkstra(s);
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
}
heap优化的dij
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 200010
using namespace std;
int T,n,m,tot,vist;
int vis[MAXN],head[MAXN],dis[MAXN];
int to[MAXN*2],cap[MAXN*2],net[MAXN*2];
int add(int u,int v,int w){
to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
}
int spfa(int now){
vis[now]=1;
for(int i=head[now];i;i=net[i])
if(dis[to[i]]>dis[now]+cap[i]){
dis[to[i]]=dis[now]+cap[i];
if(vis[to[i]]||spfa(to[i])){
vis[to[i]]=0;
return 1;
}
}
vis[now]=0;
return 0;
}
int main(){
//freopen("a.in","r",stdin);
scanf("%d",&T);
while(T--){
tot=0;vist=0;
memset(to,0,sizeof(to));
memset(cap,0,sizeof(cap));
memset(net,0,sizeof(net));
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(head,0,sizeof(head));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z);
if(z>0) add(y,x,z);
}
for(int i=1;i<=n;i++)
if(spfa(i)){
cout<<"YE5"<<endl;
vist=1;
break;
}
if(!vist) cout<<"N0"<<endl;
}
return 0;
}
spfa的dfs判负环
(二分图匹配)匈牙利算法:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
const int MAXN=1010;
using namespace std;
int n,m,e,map[MAXN][MAXN];
int ans,use[MAXN],girl[MAXN];
bool find(int x){
for(int j=1;j<=m;j++)
if(map[x][j]==1&&use[j]==0){
use[j]=1;
if(girl[j]==0||find(girl[j])){
girl[j]=x;
return 1;
}
}
return 0;
}
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;
map[x][y]=1;
}
for(int i=1;i<=n;i++){
memset(use,0,sizeof(use));
if(find(i)) ans++;
}
printf("%d",ans);
}
匈牙利
tarjin:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100010
using namespace std;
int n,m;
int sumcol;
int tot,tim,top;
int col[MAXN];
int to[MAXN],net[MAXN],head[MAXN];
int low[MAXN],dfn[MAXN],vis[MAXN],stack[MAXN],visstack[MAXN];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
}
void tarjin(int now){
stack[++top]=now;
low[now]=dfn[now]=++tim;
vis[now]=1;
visstack[now]=1;
for(int i=head[now];i;i=net[i])
if(visstack[to[i]])
low[now]=min(low[now],dfn[to[i]]);
else if(!vis[to[i]]){
tarjin(to[i]);
low[now]=min(low[now],low[to[i]]);
}
if(dfn[now]==low[now]){
sumcol++;
col[now]=sumcol;
while(stack[top]!=now){
col[stack[top]]=sumcol;
visstack[stack[top]]=0;
top--;
}
visstack[now]=0;
top--;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++)
if(!vis[i])
tarjin(i);
cout<<sumcol;
}
tarjin求强连通分量的个数
#include<map>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100010
using namespace std;
queue<int>que;
map<int,int>ma[MAXN];
int n,m;
int sumcol,ans;
int tot,tot1,tim,top;
int col[MAXN],into[MAXN];
int val[MAXN],cost[MAXN],dis[MAXN];
int to[MAXN],net[MAXN],head[MAXN];
int to1[MAXN],net1[MAXN],head1[MAXN];
int low[MAXN],dfn[MAXN],vis[MAXN],stack[MAXN],visstack[MAXN];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
}
void add1(int u,int v){
to1[++tot1]=v;net1[tot1]=head1[u];head1[u]=tot1;
}
void tarjin(int now){
stack[++top]=now;
low[now]=dfn[now]=++tim;
vis[now]=1;
visstack[now]=1;
for(int i=head[now];i;i=net[i])
if(visstack[to[i]])
low[now]=min(low[now],dfn[to[i]]);
else if(!vis[to[i]]){
tarjin(to[i]);
low[now]=min(low[now],low[to[i]]);
}
if(dfn[now]==low[now]){
sumcol++;
col[now]=sumcol;
while(stack[top]!=now){
col[stack[top]]=sumcol;
visstack[stack[top]]=0;
top--;
}
visstack[now]=0;
top--;
}
}
void spfa(int s){
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
while(!que.empty()) que.pop();
dis[s]=cost[s];
vis[s]=1;
que.push(s);
while(!que.empty()){
int now=que.front();
que.pop();
vis[now]=0;
for(int i=head1[now];i;i=net1[i])
if(dis[to1[i]]<dis[now]+cost[to1[i]]){
dis[to1[i]]=dis[now]+cost[to1[i]];
if(!vis[to1[i]]){
vis[to1[i]]=1;
que.push(to1[i]);
}
}
}
for(int i=1;i<=sumcol;i++) ans=max(ans,dis[i]);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++)
if(!vis[i])
tarjin(i);
for(int i=1;i<=n;i++)
for(int j=head[i];j;j=net[j])
if(col[i]!=col[to[j]])
if(ma[col[i]].find(col[to[j]])==ma[col[i]].end()){
ma[col[i]][col[to[j]]]=1;
into[col[to[j]]]++;
add1(col[i],col[to[j]]);
}
for(int i=1;i<=n;i++) cost[col[i]]+=val[i];
for(int i=1;i<=sumcol;i++)
if(!into[i])
spfa(i);
cout<<ans;
}
tarjin缩点
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 100010
using namespace std;
int n,m,ans;
int tot=1,tim;
int cutdian[MAXN],cutbian[MAXN];
int to[MAXN*2],net[MAXN*2],head[MAXN];
int low[MAXN],dfn[MAXN],vis[MAXN];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
to[++tot]=u;net[tot]=head[v];head[v]=tot;
}
void tarjin(int now,int pre){
low[now]=dfn[now]=++tim;
vis[now]=1;
int sum=0;
bool boo=0;
for(int i=head[now];i;i=net[i])
if((i^1)!=pre)
if(!vis[to[i]]){
sum++;
tarjin(to[i],i);
if(low[to[i]]>dfn[now]) cutbian[i/2]=1;
if(low[to[i]]>=dfn[now]) boo=1;
low[now]=min(low[now],low[to[i]]);
}
else low[now]=min(low[now],dfn[to[i]]);
if(pre==-1){
if(sum>1) cutdian[now]=1;
}
else if(boo==1) cutdian[now]=1;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;i++)
if(!vis[i])
tarjin(i,-1);
for(int i=1;i<=n;i++)
if(cutdian[i]) ans++;
cout<<ans<<endl;
for(int i=1;i<=n;i++)
if(cutdian[i])
cout<<i<<" ";
}
tarjin割边割点
最近公共祖先:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 500010
using namespace std;
int n,m,s,tot;
int to[MAXN*2],net[MAXN*2],head[MAXN];
int dad[MAXN],deep[MAXN],siz[MAXN],top[MAXN];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
to[++tot]=u;net[tot]=head[v];head[v]=tot;
}
void dfs(int now){
siz[now]=1;
deep[now]=deep[dad[now]]+1;
for(int i=head[now];i;i=net[i])
if(to[i]!=dad[now]){
dad[to[i]]=now;
dfs(to[i]);
siz[now]+=siz[to[i]];
}
}
void dfs1(int x){
int t=0;
if(!top[x]) top[x]=x;
for(int i=head[x];i;i=net[i])
if(to[i]!=dad[x]&&siz[to[i]]>siz[t])
t=to[i];
if(t){
top[t]=top[x];
dfs1(t);
}
for(int i=head[x];i;i=net[i])
if(to[i]!=dad[x]&&t!=to[i])
dfs1(to[i]);
}
int lca(int x,int y){
for(;top[x]!=top[y];){
if(deep[top[x]]<deep[top[y]])
swap(x,y);
x=dad[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
return x;
}
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(s);
dfs1(s);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
cout<<lca(u,v)<<endl;
}
}
树链剖分
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 500010
using namespace std;
int n,m,s,tot;
int dad[MAXN][20],deep[MAXN];
int to[MAXN*2],net[MAXN*2],head[MAXN];
void add(int u,int v){
to[++tot]=v;net[tot]=head[u];head[u]=tot;
to[++tot]=u;net[tot]=head[v];head[v]=tot;
}
void dfs(int now){
deep[now]=deep[dad[now][0]]+1;
for(int i=0;dad[now][i];i++)
dad[now][i+1]=dad[dad[now][i]][i];
for(int i=head[now];i;i=net[i])
if(!deep[to[i]]){
dad[to[i]][0]=now;
dfs(to[i]);
}
}
int lca(int x,int y){
if(deep[x]>deep[y]) swap(x,y);
for(int i=18;i>=0;i--)
if(deep[dad[y][i]]>=deep[x])
y=dad[y][i];
if(x==y) return x;
for(int i=18;i>=0;i--)
if(dad[x][i]!=dad[y][i]){
x=dad[x][i];
y=dad[y][i];
}
return dad[x][0];
}
int main(){
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
dfs(s);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
cout<<lca(u,v)<<endl;
}
}
倍增
网络流:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define NAXN 10001
#define MAXN 100001
using namespace std;
int n,m,s,t;
int tot=1,ans;
int cur[NAXN],lev[NAXN];
int to[MAXN*2],net[MAXN*2],cap[MAXN*2],head[NAXN];
void add(int u,int v,int w){
to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
to[++tot]=u;cap[tot]=0;net[tot]=head[v];head[v]=tot;
}
bool bfs(){
queue<int>que;
for(int i=1;i<=n;i++){
lev[i]=-1;
cur[i]=head[i];
}
lev[s]=0;
que.push(s);
while(!que.empty()){
int now=que.front();
que.pop();
for(int i=head[now];i;i=net[i])
if(lev[to[i]]==-1&&cap[i]>0){
lev[to[i]]=lev[now]+1;
que.push(to[i]);
if(to[i]==t) return true;
}
}
return false;
}
int dinic(int now,int flow){
if(now==t) return flow;
int rest=0,detal;
for(int & i=cur[now];i;i=net[i])
if(cap[i]>0&&lev[to[i]]==lev[now]+1){
detal=dinic(to[i],min(flow-rest,cap[i]));
if(detal){
rest+=detal;
cap[i]-=detal;
cap[i^1]+=detal;
if(rest==flow) break;
}
}
if(rest!=flow) lev[now]=-1;
return rest;
}
int main(){
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
while(bfs())
ans+=dinic(s,0x7fffffff);
cout<<ans;
}
网络流最大流
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define NAXN 10001
#define MAXN 100001
using namespace std;
int n,m,s,t;
int tot=1,ans;
int cur[NAXN],lev[NAXN];
int to[MAXN*2],net[MAXN*2],cap[MAXN*2],head[NAXN];
void add(int u,int v,int w){
to[++tot]=v;cap[tot]=w;net[tot]=head[u];head[u]=tot;
to[++tot]=u;cap[tot]=0;net[tot]=head[v];head[v]=tot;
}
bool bfs(){
queue<int>que;
for(int i=1;i<=n;i++){
lev[i]=-1;
cur[i]=head[i];
}
lev[s]=0;
que.push(s);
while(!que.empty()){
int now=que.front();
que.pop();
for(int i=head[now];i;i=net[i])
if(lev[to[i]]==-1&&cap[i]>0){
lev[to[i]]=lev[now]+1;
que.push(to[i]);
if(to[i]==t) return true;
}
}
return false;
}
int dinic(int now,int flow){
if(now==t) return flow;
int rest=0,detal;
for(int & i=cur[now];i;i=net[i])
if(cap[i]>0&&lev[to[i]]==lev[now]+1){
detal=dinic(to[i],min(flow-rest,cap[i]));
if(detal){
rest+=detal;
cap[i]-=detal;
cap[i^1]+=detal;
if(rest==flow) break;
}
}
if(rest!=flow) lev[now]=-1;
return rest;
}
int main(){
cin>>n>>m>>s>>t;
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
while(bfs())
ans+=dinic(s,0x7fffffff);
cout<<ans;
}
网络流最小割