大佬们,这个代码试过的测试用例结果都对,为什么会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;
}