图论板子

最短路

floyed(加最小环)

void floyed(){
	//注意初始化加赋值 
	for(int k=1;k<=n;++k){
		for(int i=1;i<k;++i){
			for(int j=i+1;j<k;++j){
				ans=min(ans,dis[i][j]+a[i][k]+a[k][j]);
			}
		}
		for(int i=1;i<=n;++i){
			for(int j=1;j<=n;++j){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]) ;
			}
		}
	}
} 

SPFA(加判断负环)

void spfa(int s){
	for(int i=1;i<=n;++i) dis[i]=INF;
	dis[s]=0;
	q.push(s);
	while(!q.empty()){
		int u=q.front();
		vis[u]=0;q.pop();
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				pre[v]=u;//记录路径用
				if(!vis[v]){
					q.push(v);
					vis[v]=1;
              				/*in[v]++
                    			if(in[v]>n){
                    			//如果一个顶点的入队个数大于n,即有负环 
                    			return true; 
                    			}*/
				} 
			}
		}
	}
}

堆优化dijkstra

struct node{
	int w,s;
	node(){}
	node(int a,int b){
		s=a;
		w=b;
	}
	bool operator<(const node &a)const{
		return w>a.w;
		//小根堆 
	}
};
void dijkstra(int s){
	for(int i=1;i<=n;++i) dis[i]=INF;
	dis[s]=0;
	q.push(node(s,0));
	while(!q.empty()){
		int u=q.top().s;
		if(vis[u]) continue;
		vis[u]=1;q.pop();
		for(int i=head[u];i;i=e[i].next){
			int v=e[i].to;
			if(dis[v]>dis[u]+e[i].w){
				dis[v]=dis[u]+e[i].w;
				q.push(node(v,dis[v]));
			}
			/*
			if(dis[v]>max(e[i].w,dis[u])){
				dis[v]=max(e[i].w,dis[u]);
				求最短路径最大值
			}
			*/
		}
	}
}

欧拉欧拉欧拉欧拉(欧拉回路)

void dfs(int t){
	for(int i=1;i<=n;++i){
		if(a[t][i]){
			a[t][u]--;a[i][t]--;
			dfs(i);
		}
	}
	pr[++pr[0]]=t;
	//注意倒序输出 
} 
void oula(){
	for(int i=1;i<=m;++i){
		a[x][y]++;a[y][x]++;
		du[x]++;du[y]++;
		//存边 
	}
	int st=1;
	for(int i=1;i<=n;++i){
		if(du[i]&1){
			st=i;
			break;
		}
		//找奇点 
	}
	dfs(st);
}

最小生成树

kruslal

struct node{
	int x,y,w;
	node(){}
	node(int a,int b,int c):x(a),y(b),w(c){}
	bool operator <(const node &c)const{
		return w<c.w;
	}
}e[maxn];
int kruskal(){
	int mst=0,k=0;
	for(int i=1;i<=n;++i) f[i]=i;
	//并查集初始化 
   	sort(e+1,e+1+m);
	for(int i=1;i<=m;++i){
		if(find(e[i].x)!=find(e[i].y)){
			merge(e[i].x,e[i].y);
			mst+=e[i].w;
			k++;
			if(k==n-1){
				//构成最小树 
				break;
			}
		}
	}
	return mst; 
}

最小差值生成树

#include<bits/stdc++.h>
#define  R register int
using namespace std;
int n,m;
int f[1000001];
int cnt;
struct node{
	int x,y,w;
	node(){}
	node(int a,int b,int c):x(a),y(b),w(c){}
	bool operator <(const node &c)const{
		return w<c.w;
	}
}kar[1000001];
int find(int x){
	if(f[x]!=x) f[x]=find(f[x]);
	return f[x];
}
void merge(int x,int y){
	int rx=find(x);
	int ry=find(y);
	f[ry]=rx;
}
void pre(){
	for(R i=1;i<=m;++i) f[i]=i;
}
int mst,ans=999999999;
void kruskal(){
	mst=0;
	int k=0;
	sort(kar+1,kar+1+m);
	for(R j=1;j<=m;++j){
		k=0;pre();//初始化 
		for(R i=j;i<=m;++i){
		//从最小值开始枚举 
			if(find(kar[i].x)!=find(kar[i].y)){
				merge(kar[i].x,kar[i].y);
				k++;
				if(k==n-1){
					ans=min(ans,kar[i].w-kar[j].w);
					//最大值-最小值 
					break;
				}
			}
		}
		if(k<n-1||ans==0){
			//某种优化 
			break;
		}
	}
}
int main(){
	scanf("%d%d",&n,&m);
	int x,y,w; 
	for(R i=1;i<=m;++i){
		scanf("%d %d %d",&x,&y,&w);
		if(x==y){
			//无用边 
			continue;
		}else{
			kar[i].x=x;
			kar[i].y=y;
			kar[i].w=w;
		}
	}
	kruskal();
	if(ans==9999999) cout<<-1;
	else cout<<ans;
	return 0;
}

LCA

树上倍增:-)

dfs(1,0,1)//调用入口 
void dfs(int u,int fa,int dep){
	re[u]=dep;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==fa)continue;
		f[v][0]=u;
		dfs(v,u,dep+1);
	}
	//建立父子关系 
} 
void pre(){
    for(int j=1;(1<<j)<=n;++j){
        for(int i=1;i<=n;++i){
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
}
int lca(int x,int y){
    if(re[x]<re[y]) swap(x,y);
    for(int i=20;i>=0;i--){
        if(re[f[x][i]]>=re[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(int i=20;i>=0;i--){
        if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}

最小瓶颈生成树

最小生成树的最大边,反之同理

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=10005;
int head[maxn],n,m,R,cnt;
int fa[maxn],f[maxn][51];
int minn[maxn][51];
bool za[maxn];
int re[maxn<<1];
struct bian{
	int x,y,w;
	bool operator <(const bian &a)const{
		return w>a.w;
	}
}e2[maxn];
struct ed{
	int next,to,w;
}e[maxn<<1];
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
void add(int u,int v,int w){
	e[++cnt].to=v;
	e[cnt].next=head[u];
	e[cnt].w=w;
	head[u]=cnt;
}
int root=1;
int find(int x){
	if(fa[x]!=x) fa[x]=find(fa[x]);
	return fa[x];
}
void bing(int x,int y){
	int rx=find(x);
	int ry=find(y);
	fa[rx]=ry;
}
void kruskal(){
	for(register int i=1;i<=n;++i) fa[i]=i;
	int k=0;
	for(register int i=1;i<=m;++i){
		if(find(e2[i].x)!=find(e2[i].y)){
			bing(e2[i].x,e2[i].y);
			add(e2[i].x,e2[i].y,e2[i].w);
			add(e2[i].y,e2[i].x,e2[i].w);
			root=e2[i].x;
			k++;
			if(k==n-1){
				return;
			}
		}
	}
}
int lca(int x,int y){
	if(re[x]<re[y]) swap(x,y);
	int tot=99999999;
	for(register int j=20;j>=0;j--){
		if(re[x]-(1<<j)>=re[y]){
			tot=min(tot,minn[x][j]);
			x=f[x][j];	
		} 
		if(x==y) return tot;
		//注意这里直接返回 
	}
	for(register int j=20;j>=0;j--){
		if(re[x]>=(1<<j)&&f[x][j]!=f[y][j]){
			tot=min(tot,min(minn[x][j],minn[y][j]));
			x=f[x][j];
			y=f[y][j];
		}
	}
	tot=min(tot,minn[x][0]);
	tot=min(tot,minn[y][0]);
	return tot;
}
void dfs(int u,int fa,int dep){
	re[u]=dep;
	for(register int i=head[u];i;i=e[i].next){
		int v=e[i].to,w=e[i].w;
		if(fa!=v){
			f[v][0]=u;
			minn[v][0]=w;
			dfs(v,u,dep+1);	
		}
	}
}
int main(){
	int q=0;
	n=read();m=read();
	for(register int i=1;i<=m;++i){
		int x,y,w;
		x=read();y=read();w=read();
		e2[i].x=x;
		e2[i].y=y;
		e2[i].w=w;
	}
 	sort(e2+1,e2+1+m);
 	kruskal();
	q=read();
	memset(minn,0x7f,sizeof(minn));
	dfs(root,0,1);
	for(register int j=1;(1<<j)<=n;++j){
		for(register int i=1;i<=n;++i){
			f[i][j]=f[f[i][j-1]][j-1];
			minn[i][j]=min(minn[i][j-1],minn[f[i][j-1]][j-1]);
		}
	}
	for(register int i=1;i<=q;++i){
		int x,y;
		x=read();y=read();
		if(find(x)!=find(y)){
			printf("-1\n");
			continue;
		}
		int z=lca(x,y);
		printf("%d\n",z);
	}
	return 0;
}

dfs序

void dfs(int u,int fa){
	tot++;
	in[u]=tot;
	for(register int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v!=fa) {
			dfs(v,u);
			//out[u]=++tot; 欧拉1 
		}
	}
	out[u]=tot; 
	//out[u]=++tot; 欧拉2
}

tarjan

强♂联通分量

void tarjan(int u){
	tot++;vis[u]=1;s[++top]=u;
	dfn[u]=low[u]=tot;
	for(register int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(!dfn[v]) {
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}else if(vis[v]){
			low[u]=min(low[u],dfn[v]);
		}
	}
	if(low[u]==dfn[u]){
		int y;z++;
		do{
			y=s[top--];
			vis[y]=0;
			belong[y]=z;
		}while(y!=u);
	} 
}

割点

void tarjan(int u,int fa){
	tot++;
	dfn[u]=low[u]=tot;
	int son=0;bool F=1;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==fa&&F){
			F=0;continue; 
		}
		if(!dfn[v]) {
			tarjan(v,u);son++;
			low[u]=min(low[u],low[v]);
			if(dfn[u]<=low[v]){
				//割点存在
				if(u!=root||son>1){
					dot[u]=1;
				} 
			}
		}else{
			low[u]=min(low[u],dfn[v]);
		}
	}
}

点双联通分量

void tarjan(int u,int fa){
	tot++;s[++top]=u;
	dfn[u]=low[u]=tot;
	int son=0;bool F=1;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v==fa&&F){
			F=0;continue; 
		}
		if(!dfn[v]) {
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(dfn[u]<=low[v]){
				//割点存在
				cut[u]=1;	
              			dslt[cnt].push_back(u);
				int y=0;cnt++;
				do{
					y=s[top--];
					dslt[cnt].push_back(y);
				}while(y!=v);	
			}
		}else low[u]=min(low[u],dfn[v]);
	}
	if(fa==0&&son==1) cut[u]=0;
}

割边

void tarjan(int u){
	tot++;
	dfn[u]=low[u]=tot;
	for(int i=head[u];i!=-1;i=e[i].next){
		int v=e[i].to;
		if(i==p[u]^1) continue; 
		if(!dfn[v]) {
			p[v]=i;//记录编号 
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(dfn[u]<low[v]){
				//割边存在
				cnt++;
				cut[i]=cut[i^1]=1; 
			}
		}else low[u]=min(low[u],dfn[v]);
	}
}

边双联通分量

//存边时下标务必从0存储 
void tarjan(int u,int eid){
	tot++;vis[u]=1;s[++top]=u;
	dfn[u]=low[u]=tot;
	for(int i=head[u];i!=-1;i=e[i].next){
		int v=e[i].to;int id=e[i].id;
		if(id==eid^1) continue; 
		if(!dfn[v]) {
			tarjan(v,id);
			low[u]=min(low[u],low[v]);
		}else low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u]){
		cut[eid]=1;
		cnt++;
		int x;
		do{
			x=s[top--];
			bslt[cnt].push_back(x);
		}while(x!=u);
	}
}

矿场搭建(割点做法)

#include <bits/stdc++.h> 
#define ll long long
using namespace std;
const int maxn=600;
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*w;
}
int head[maxn],cnt,n,tot,dfn[maxn],low[maxn];
int dl[maxn],vis[maxn],num,cut;
int root=1;
struct ED{
	int to,next;
}e[maxn<<1];
ll solu,total;
bool zio[maxn];
void add(int u,int v){
	e[++cnt].to=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
stack<int> s;
void tarjan1(int u){
	++tot;
	dfn[u]=tot;
	low[u]=tot;
	int wenqizhi=0;
	for(register int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(!dfn[v]){
			wenqizhi++;
			tarjan1(v);
			low[u]=min(low[u],low[v]);
			if(dfn[u]<=low[v]){
				if(u!=root||wenqizhi>1){
					zio[u]=1;
				} 
			}
		}else{
			low[u]=min(low[u],dfn[v]);
		}
	}
}
void dfs(int u,int fa){
	vis[u]=fa;
	num++;
	for(register int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(vis[v]!=fa&&zio[v]){
			cut++;
			vis[v]=fa;
		}
		if(vis[v]) continue;
		dfs(v,fa);
	}
	tot=max(tot,dl[u]);
}
int main(){
	int p=0;
	while(1){
		p++;
		cnt=0;tot=0;
		total=0;solu=1;
		memset(head,0,sizeof(head));
		memset(dfn,0,sizeof(dfn));
		memset(low,0,sizeof(low));
		memset(zio,0,sizeof(zio));
		memset(vis,0,sizeof(vis));
		memset(dl,0,sizeof(dl));
		memset(e,0,sizeof(struct ED)*maxn);
		n=read();
		if(n==0) break;
		int nn=0;
		for(register int i=1;i<=n;++i){
			int x,y;x=read();y=read();
			add(x,y);add(y,x);
			nn=max(nn,max(x,y));
		}
		for(register int i=1;i<=nn;++i){
			if(!dfn[i]) {
				root=i;
				tarjan1(i);
			}
		}
		int opt=0;
		for(register int i=1;i<=nn;++i){
			if(!zio[i]&&!vis[i]) {
				num=0;
				cut=0;
				dfs(i,++opt);
				if(cut==0){
					total+=2;
					solu*=(long long)num*(num-1)/2;
				}
				if(cut==1){
					total++;
					solu*=(long long)num;
				}
			}
		}
		printf("Case %d: %lld %lld\n",p,total,solu);
	}
	return 0;
} 
//通过查询每个连通块的割点数量来求值 

未完。

posted @ 2022-05-14 21:46  Broken_Eclipse  阅读(48)  评论(0)    收藏  举报

Loading