A国有n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
最大生成树+lca求最小边权
有这么多条边,但每次都只会走那几条边权最大的边,其实,就是一棵最大生成树嘛。
把树找到后,设d[x][i]表示从x到f[x][i]中的最小边权,d[x][i]=min(d[x][i-1],d[f[x][i-1]][i-1])。
接下来的活儿交给lca。
想要优化一个算法,不一定要用回这个算法。
#include
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=10010,maxm=50010,maxq=30010;
int n,m;
struct E{int x,y,c,next;}a[maxm],e[maxn*2];int len=1,last[maxn];
bool cmp(E e1,E e2){return e1.c>e2.c;}//debug 最大生成树
void ins(int x,int y,int c)
{
e[++len]=(E){x,y,c,last[x]};last[x]=len;
}
int fa[maxn];
int findfa(int x)
{
if(fa[x]==x) return x;
return fa[x]=findfa(fa[x]);
}
void kruskal()
{
for(int i=1;i<=n;i++) fa[i]=i;
sort(a+1,a+m+1,cmp);
for(int i=1;i<=m;i++)//debug 遍历所有边(不一定满n-1条)
{
int fx=findfa(a[i].x),fy=findfa(a[i].y);
if(fx!=fy)
{
ins(a[i].x,a[i].y,a[i].c);
ins(a[i].y,a[i].x,a[i].c);
fa[fx]=fy;
}
}
}
int head,tail,q[maxn];
int dep[maxn],f[maxn][20],d[maxn][20];
void bfs(int S)
{
head=0,tail=1;q[0]=S;
dep[S]=1;
for(int i=0;i<=16;i++) d[S][i]=inf;
while(head=0;i--)
if(dep[f[x][i]]>=dep[y])
{
re=min(re,d[x][i]);
x=f[x][i];
}
if(x==y) return re;
for(int i=16;i>=0;i--)
if(f[x][i]!=f[y][i])
{
re=min(re,min(d[x][i],d[y][i]));
x=f[x][i],y=f[y][i];
}
if(f[x][0]==f[y][0]) return min(re,min(d[x][0],d[y][0]));//debug 别忘了与f[x/y][0]之间的边
return inf;//x和y没有公共祖先
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].c);
kruskal();
for(int i=1;i<=n;i++)//因为不连通,所以每个点都要检查
if(!dep[i]) bfs(i);
int Q;scanf("%d",&Q);
while(Q--)
{
int x,y,ans;
scanf("%d%d",&x,&y);
if(findfa(x)!=findfa(y)){puts("-1");continue;}//用并查集判是否连通
ans=lca(x,y);
printf("%d\n",ans==inf?-1:ans);
}
return 0;
}