货车运输

货车运输

题目描述
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啊算法优化时间
还有树链剖分啊动态树的做法什么的,
树链剖分太恐怖了,动态树不会。。

猜你喜欢

转载自blog.csdn.net/beautiful_cxw/article/details/80971713
今日推荐