货车运输
题目描述
AA 国有 n n 座城市,编号从 1 1 到 nn ,城市之间有 mm 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 qq 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入输出格式
输入格式:
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行 3 3 个整数 x, y, z,每两个整数之间用一个空格隔开,表示从 x号城市到 y号城市有一条限重为z 的道路。注意: x 不等于 ,两座城市之间可能有多条道路 。
接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意: x 不等于 y 。
输出格式:
共有 qq 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出 -1。
题解:emmm第一眼看过去还觉得很烦,觉得会怎么样怎么样,哎,现在就会在想,图论嘛,很多东西并不难(毕竟NOIP),只是打起来会很烦,代码会多,细节也会多,要仔细认真的打代码,打多了就习惯了。(可惜我打的不多,遇到还是会手忙脚乱)
emmm就是,在最大生成树上LCA。
为什么呢,因为,你可以很容易得到,但凡所要求的最大限重的边,是必然的会在这棵最大生成树上的(本身连接的也是最大的边)
所以,就是以某个点为根,遍历一遍,然后在这颗树上,求起点和重点的最近公共祖先。
克鲁斯卡尔啊普林姆应该都可以的,
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100005;
const int INF = 2147483640;
int n,m,tot = 0;
int first[MAXN],next[MAXN],dis[MAXN],num[MAXN],rank[MAXN],fa[MAXN],val[MAXN],deep[MAXN];
bool visit[MAXN];
struct edge
{
int f,t,v;
}e[MAXN],l[MAXN<<1];
bool cmp(edge a,edge b)
{
return a.v>b.v;
}
int find(int x)
{
return x==num[x]?x:num[x]=find(num[x]);
}
void merge(int x,int y)
{
x=find(x);
y=find(y);
if(rank[x]>rank[y])
swap(x,y);
num[x]=y;
if(rank[x]==rank[y])
rank[y]++;
return;
}
void kru()
{
for(int i=1;i<=n;i++)
num[i] = i;
memset(rank,0,sizeof(rank));
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++)
{
int f=e[i].f;
int t=e[i].t;
if(!find(f)==find(t))
{
l[++ tot]=(edge){f,t,e[i].v};
next[tot]=first[f];
first[f]=tot;
l[++tot]=(edge){t,f,e[i].v};
next[tot]=first[t];
first[t]=tot;
merge(f,t);
}
}
return;
}
void dfs(int x,int f,int va)//求用做lca的树
{
fa[x]=f;
val[x]=va;
visit[x]=true;
deep[x]=deep[f] + 1;
for(int i=first[x];i!=-1;i=next[i])
{
int w=l[i].t;
if(visit[w]) continue;
dfs(w,x,l[i].v);
}
return;
}
int ask(int x,int y)
{
if(!find(x)==find(y)) return-1;
int ans=INF;
if(deep[x]<deep[y])
swap(x,y);
while(deep[x]>deep[y])
{
ans=min(ans,val[x]);
x=fa[x];
}
while(x!=y)
{
ans=min(ans,val[x]);
ans=min(ans,val[y]);
x=fa[x];
y=fa[y];
}
return ans;
}
int q,f,t;
int main()
{
freopen("truck.in","r",stdin);
freopen("truck.out","w",stdout);
memset(first,0xff,sizeof(first));
tot=0;
scanf("%d %d",&n,&m);
for(int i=1; i<=m; i++)
scanf("%d%d%d",&e[i].f,&e[i].t,&e[i].v);
kru();
for(int i=1;i<=n;i++)
if(!visit[i])dfs(i,0,0);
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&f,&t);
printf("%d\n",ask(f,t));
}
return 0;
}
lca的话时间会久一点,就可以用倍增啊tarjan啊算法优化时间
还有树链剖分啊动态树的做法什么的,
树链剖分太恐怖了,动态树不会。。