pts20蒟蒻求助
查看原帖
pts20蒟蒻求助
671223
OAIM楼主2024/4/2 11:42

大佬们,这个代码试过的测试用例结果都对,为什么会WA那么多点呢?蒟蒻求助。

//网络稳定性

//每条路径的稳定性为经过的连接中最低的稳定性
//求指定两个设备之间的最高通信稳定性
//不存在输出-1
//预处理 
//无向图 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;

const int N = 1e5 + 10;
const int M = 3e5 + 10;
const int Q = 1e5 + 10;
const int INF = 1e6 + 10;

int n;//设备数
int m;//物理连接数
int q;//询问数
int p[N];//祖先节点 
int fa[N];//记录父亲节点
int rt[N];//根节点
int cnt = 0;//生成树个数 
int dep[N];//每个点的深度 
int h[N],e[M * 2],ne[M * 2],w[M * 2],idx = 0;//邻接表 
int f[N][21];//f[i][j]:从节点i向上走2^j步的点 
int dp[N][21];//dp[i][j]:从节点i向上走2^j步的稳定性 
bool st[N];//各个点的深度是否已经确定了 

struct Edge{
	int u,v,w;
	
	bool operator < (const Edge &e) const{
		return w > e.w;
	}
}edges[M];//物理连接

//添加邻接表中的边
void add(int u,int v,int ww){
	e[idx] = v;
	w[idx] = ww;
	ne[idx] = h[u];
	h[u] = idx;
	idx++;
} 

//初始化并查集
void init(){
	for(int i = 1;i <= n;i++){
		p[i] = i;
	}
} 

//查找祖先节点
int find(int x){
	if(p[x] != x){
		p[x] = find(p[x]);
	}
	return p[x];
} 

//克鲁斯卡尔算法
void kruskal(){
	//按照权值从大到小为物理连接排序
	sort(edges,edges + m);
	//初始化并查集
	init(); 
	//初始化邻接表
	memset(h,-1,sizeof(h)); 
	//初始化dp
	//memset(dp,0x3f,sizeof(dp)); 
	for(int i = 0;i <= n;i++){
		for(int j = 0;j <= 20;j++){
			dp[i][j] = INF;
		}
	}
	
	//从大到小遍历所有边
	for(int i = 0;i < m;i++){
		//printf("i=%d\n",i);
		int a = edges[i].u,b = edges[i].v,c = edges[i].w;
		//判断这条边上的两点是否已经在一个集合中了
		int aa = find(a);
		int bb = find(b);
		if(aa != bb){
			//不在一个集合中
			p[aa] = bb;
			fa[aa] = bb;
			add(a,b,c);
			add(b,a,c);
		} 
	} 
} 

//求各个点的深度
void dfs(int x,int p,int val){
	//printf("x=%d\n",x);
	dep[x] = dep[p] + 1;
	st[x] = true;
	f[x][0] = p;
	dp[x][0] = val;
	//printf("dp[%d][0]=%d\n",x,dp[x][0]);
	//printf("f[%d][0]=%d\n",x,f[x][0]);
	//更新f和dp 
	for(int i = 1;i <= 20;i++){
		f[x][i] = f[f[x][i - 1]][i - 1];
		//printf("f[%d][%d]=%d\n",x,i,f[x][i]);
		dp[x][i] = min(dp[x][i - 1],dp[f[x][i - 1]][i - 1]);
		//printf("dp[%d][%d]=%d\n",x,i,dp[x][i]);
	} 
	
	//遍历所有相邻节点 
	for(int i = h[x];i != -1;i = ne[i]){
		int j = e[i];
		if(st[j]){
			continue;
		}
		//dp[j][0] = w[i];
		//printf("dp[%d][0]=%d\n",x,dp[x][0]);
		//printf("j=%d\n",j);
		dfs(j,x,w[i]);
	}
} 

//最近公共父节点算法
int lca(int x,int y){
	//printf("find(%d)=%d,find(%d)=%d\n",x,find(x),y,find(y));
	if(find(x) != find(y)){
		//不连通
		return -1; 
	}
	
	int res = INF;
	
	//printf("dep[%d]=%d,dep[%d]=%d\n",x,dep[x],y,dep[y]);
	
	//保证x节点更深 
	if(dep[x] < dep[y]){
		swap(x,y);
	}
	//printf("x=%d,y=%d\n",x,y);
	//找到同一层
	while(dep[x] > dep[y]){
		//printf("(int)log2(dep[%d] - dep[%d])=%d\n",x,y,(int)log2(dep[x] - dep[y]));
		//printf("f[%d][%d]=%d\n",x,(int)log2(dep[x] - dep[y]),f[x][(int)log2(dep[x] - dep[y])]);
		res = min(res,dp[x][(int)log2(dep[x] - dep[y])]);
		x = f[x][(int)log2(dep[x] - dep[y])];
		//printf("x=%d\n",x);
		//printf("dep[%d]=%d,dep[%d]=%d\n",x,dep[x],y,dep[y]);
		//printf("res=%d\n",res);
	} 
	
	//printf("res=%d\n",res);
	
	if(x == y){
		//y就是x的父节点
		return res; 
	}
	
	//移动两个点找最近公共父节点
	for(int i = log2(dep[x]);i >= 0;i--){
		if(i == 0){
			res = min(res,dp[x][i]);
			res = min(res,dp[y][i]);
			//printf("res=%d\n",res);
			//printf("dp[%d][%d]=%d,dp[%d][%d]=%d\n",x,i,dp[x][i],y,i,dp[y][i]);
		}
		if(f[x][i] != f[y][i]){
			//没找到父节点
			res = min(res,dp[x][i]);
			res = min(res,dp[y][i]);
			x = f[x][i];
			y = f[y][i]; 
			//printf("dp[%d][%d]=%d,dp[%d][%d]=%d\n",x,i,dp[x][i],y,i,dp[y][i]);
		}
		//printf("res=%d\n",res);
	} 
	
	return res;
} 

int main(){
	//输入
	scanf("%d %d %d",&n,&m,&q);
	for(int i = 0;i < m;i++){
		scanf("%d %d %d",&edges[i].u,&edges[i].v,&edges[i].w);
		//add(edges[i].u,edges[i].v,edges[i].w);
		//add(edges[i].v,edges[i].u,edges[i].w);
	} 
	//生成最大生成树 
	kruskal();
	//找根节点
	for(int i = 1;i <= n;i++){
		if(!fa[i]){
			//没有父节点
			cnt++;
			rt[cnt] = i; 
			//printf("rt[%d]=%d\n",cnt,i);
		}
	} 
	//求各个点的深度 
	for(int i = 1;i <= cnt;i++){
		//printf("rt[%d]=%d\n",i,rt[i]);
		dfs(rt[i],0,INF);
	}
	int x,y;
	for(int i = 0;i < q;i++){
		scanf("%d %d",&x,&y);
		//求最近公共父节点 
		int res = lca(x,y);
		if(x == y){
			res = 0;
		} 
		//输出
		printf("%d\n",res);
	}
	
	return 0;
} 
2024/4/2 11:42
加载中...