题目描述
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。
输出
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。
比赛时我姿势太少,直接写的暴力,滚粗了……
正解:
先根据原图找一个最大生成树。
每一次询问就是找 a,b 的最近公共祖先。
由于数据大,就用树上路径倍增算法找最近公共祖先。
蒟蒻第一次学习树上路径倍增算法,若大神对以下解释有补充,欢迎留言,谢谢。O(∩_∩)O
先预处理:
用数组 f[i][j] 表示节点i的第 2j 个祖先,那么 f[i][0] 就是节点i的父亲,得到递推式: f[i][j]=f[[i][j−1]][j−1]
令数组 g[i][j] 表示节点i到第 2j 个祖先的最小边权,递推式: g[i][j]=min(g[i][j−1],g[f[i][j−1]][j−1])
对每一次询问,找 a,b 的最近公共祖先。
首先要统一 a,b 的深度(当然是将深的那个节点上移,使得深度一致),之后使用倍增算法寻找最近公共祖先。
结果我在实现过程中把if(u==v)return ans;(在代码第90行)自作主张地删了,就WA- -
#include
#include
#include
#include
#define MAXM 50050
#define MAXN 10050
#define MAXD 22
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int INF=2147483647;
int n ,m ;
int fa[MAXN] ;
int f[MAXN][MAXD] ,g[MAXN][MAXD] ,dep[MAXN] ;
bool vis[MAXN] ;
int getroot(int a)
{
if(fa[a]==a)return a;
return fa[a]=getroot(fa[a]);
}
struct Edge
{
int u ,v ,w ;
bool operator < (const Edge &a)const
{return w>a.w ;}
}e[MAXM];
struct node
{
int v ,w ;
node *next ;
}edge[MAXN<<1] ,*adj[MAXN] ,*code=edge ;
void add(int a,int b,int c)
{
node *p=++code ;
p->v=b ,p->w=c ,p->next=adj[a] ;
adj[a]=p ;
}
void kruskal()
{
sort(e,e+m);
int a ,b ;
for(int i=0;iif(a!=b)
{
fa[a]=b;
add(e[i].u,e[i].v,e[i].w);
add(e[i].v,e[i].u,e[i].w);
}
}
}
void dfs(int u)
{
int v ;
for(node *p=adj[u];p!=NULL;p=p->next)
if(!vis[(v=p->v)])
{
vis[v]=1;
f[v][0]=u ,g[v][0]=p->w ,dep[v]=dep[u]+1 ;
dfs(v);
}
}
int adjust(int &u,int high)
{
int ans=INF;
for(int i=MAXD-1;i>=0;--i)
if(dep[f[u][i]]>=high)
{
ans=min(ans,g[u][i]);
u=f[u][i];
}
return ans;
}
int solve(int u,int v)
{
if(getroot(u)!=getroot(v)||u==v)return -1;
int ans=INF;
if(dep[u]!=dep[v])
ans=dep[u]>dep[v]?adjust(u,dep[v]):adjust(v,dep[u]);
if(u==v)return ans;
for(int j=MAXD-1;j>=0;--j)
if(f[u][j]!=f[v][j])
{
ans=min(ans,min(g[u][j],g[v][j]));
u=f[u][j] ,v=f[v][j] ;
}
ans=min(ans,min(g[u][0],g[v][0]));
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)fa[i]=i ;
for(int i=0;iscanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
kruskal();
for(int i=1;i<=n;++i)
if(!vis[i])
{
vis[i]=1 ,dep[i]=0 ;
dfs(i);
g[i][0]=INF;
f[i][0]=i;
}
for(int j=1;jfor(int i=1;i<=n;++i)
{
f[i][j]=f[f[i][j-1]][j-1] ;
g[i][j]=min(g[i][j-1],g[f[i][j-1]][j-1]);
}
int T ,a ,b ;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&a,&b);
printf("%d\n",solve(a,b));
}
return 0;
}