Codevs3287 货车运输

  • 题目大意:给定一张无向图,求出两点间所有路径中最小边的最大值。
  • 思路:首先我们需要求出一个能连通所有点且能使各边满足题意的简化图,那么它是什么呢?显然是最大生成树。最大生成树既能联通所有点,又能使边符合题意,因为如果存在一个更大的边,该边便会被纳入最大生成树,从而保证了最小边最大化。这样处理后的图是一棵无根树,需要运用dfs确定父子关系。最后处理询问时,找到两个询问点的LCA即能解决问题。
  • 解决方案:将kruskal( )反过来按边权从大到小排序,询问时如果find(u)!=find(v)则输出-1,否则进入query( )。在query( )中,如果使用暴力找LCA,只需让两节点在中途记录下边权的最小值最后输出;若使用倍增法,需要利用数组g[i,j]表示从节点i向上跳2j步中载重最小的道路权值,则有g[i,j]=min(g[i,j-1],g[fa[i,j-1],j-1])。
  • 代码如下:

    先上暴力版:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct edgetype
{
    int u,v,len;
    edgetype(int u=0,int v=0,int len=0):u(u),v(v),len(len){}
};
struct node
{
    int id,len;
    node(int id=0,int len=0):id(id),len(len){}
};
int n,m,q,cnt=0,ans;
edgetype edge[50005];
int fa[10005],f[10005],g[10005],dep[10005];
bool vis[10005];
vector<node> son[10005];

int getfa(int x)
{
    if (fa[x]==x)
      return x;
    fa[x]=getfa(fa[x]);
    return fa[x];
}

void unite(int a,int b)
{
    fa[getfa(a)]=getfa(fa[b]);
}

int comp(edgetype a,edgetype b)
{
    return a.len>b.len;
}

void kruskal()
{
    sort(edge+1,edge+m+1,comp);
    int ingraph=0,p=0;
    while (ingraph<=n-1 && p<m)
    {
        p++;
        if (getfa(edge[p].u)!=getfa(edge[p].v))
        {
            unite(edge[p].u,edge[p].v);
            son[edge[p].u].push_back(node(edge[p].v,edge[p].len));
            son[edge[p].v].push_back(node(edge[p].u,edge[p].len));
            ingraph++;
        }
    }
}

void build(int root,int depth)
{
    dep[root]=depth;
    vis[root]=1;
    vector<node>::iterator it;
    for (it=son[root].begin();it!=son[root].end();++it)
    {
        if (!vis[(*it).id])
        {
            f[(*it).id]=root;
            g[(*it).id]=(*it).len;
            build((*it).id,depth+1);
        }
    }
}

void query(int u,int v)
{
    ans=1000000000;
    if (dep[u]<dep[v])
      swap(u,v);
    while (dep[u]!=dep[v])
    {
        ans=min(ans,g[u]);
        u=f[u];
    }
    if (u==v)
    {
        printf("%d\n",ans);
    }
    else
    {
        while (u!=v)
        {
            ans=min(ans,min(g[u],g[v]));
            u=f[u];
            v=f[v];
        }
        printf("%d\n",ans);
    }

}

void init()
{
    scanf("%d%d",&n,&m);
    int u,v,len;
    memset(vis,0,sizeof(vis));
    for (int i=1;i<=n;++i)
      for (int j=0;j<=20;++j)
        g[i]=1000000000;
    for (int i=1;i<=n;++i)
      fa[i]=i;
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&u,&v,&len);
        edge[i]=edgetype(u,v,len);
    }
    kruskal();
    build(1,1);
    scanf("%d",&q);
    int x,y;
    while (q--)
    {
        scanf("%d%d",&x,&y);
        if (getfa(x)!=getfa(y))
        {
            printf("-1\n");
            continue;
        }
        query(x,y);
    }
}

int main()
{
    init();
    return 0;
}

然后是t14t41t大神的倍增版(自己的总是WA……):

#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxm 10005
#define maxn 100005
#define oo 1000000000
#define nil 0
using namespace std;
int n, m, q;
int anc[maxm], ufs[maxm];
struct edges
{
    int s, t, maxi;
    edges(int s = 0, int t = 0, int maxi = 0) :s(s), t(t), maxi(maxi) {}
    bool operator < (const edges& b) const
    {
        return maxi > b.maxi;
    }
}edge[maxn >> 1];
int u[maxn], v[maxn], w[maxn], nxt[maxn], pnt[maxm], e;
int fa[15][maxm], g[15][maxm], dep[maxm];
bool vis[maxm];
int findanc(int x) { return x == anc[x] ? x : anc[x] = findanc(anc[x]); }
int findufs(int x) { return x == ufs[x] ? x : ufs[x] = findufs(ufs[x]); }
void add(edges& a)
{
    u[++e] = a.s; v[e] = a.t; w[e] = a.maxi;
    nxt[e] = pnt[a.s]; pnt[a.s] = e;
    u[++e] = a.t; v[e] = a.s; w[e] = a.maxi;
    nxt[e] = pnt[a.t]; pnt[a.t] = e;
}
void dfs(int rot)
{
    vis[rot] = true;
    for(int j = pnt[rot]; j != nil; j = nxt[j])
    {
        if(!vis[v[j]])
        {
            fa[0][v[j]] = rot;
            g[0][v[j]] = w[j];
            dep[v[j]] = dep[rot] + 1;
            dfs(v[j]);
        }
    }
}
void init()
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i) ufs[i] = anc[i] = i;
    for(int i = 0; i < m; ++i)
    {
        scanf("%d%d%d", &edge[i].s, &edge[i].t, &edge[i].maxi);
        if(findufs(edge[i].s) != findufs(edge[i].t))
        {
            ufs[findufs(edge[i].s)] = findufs(edge[i].t);
        }
    }
    sort(edge, edge + m);
    int tot = 0;
    for(int i = 0; i < m && tot < n - 1; ++i)
    {
        if(findanc(edge[i].s) != findanc(edge[i].t))
        {
            anc[findanc(edge[i].s)] = findanc(edge[i].t);
            add(edge[i]);
            ++tot;
        }
    }
    memset(vis, 0, sizeof(vis));
    memset(g, 0x3f, sizeof(g));
    for(int i = 1; i <= n; ++i) if(!vis[i])
    {
        fa[0][i] = nil;
        dep[i] = 1;
        dfs(i);
    }
    for(int j = 1; j <= 14; ++j) for(int i = 1; i <= n; ++i)
    {
        fa[j][i] = fa[j - 1][fa[j - 1][i]];
        g[j][i] = min(g[j][i], min(g[j - 1][i], g[j - 1][fa[j - 1][i]]));
    }
    scanf("%d", &q);
}
void work()
{
    int a, b, ans;
    while(q--)
    {
        ans = oo;
        scanf("%d%d", &a, &b);
        if(findufs(a) != findufs(b))
        {
            puts("-1");
            continue;
        }
        if(dep[a] < dep[b]) swap(a, b);
        for(int j = 14; j >= 0; --j)
        {
            if(dep[fa[j][a]] >= dep[b])
            {
                ans = min(ans, g[j][a]);
                a = fa[j][a];
            }
        }
        if(a != b)
        {
            for(int j = 14; j >= 0; --j)
            {
                if(fa[j][a] != fa[j][b])
                {
                    ans = min(ans, g[j][a]);
                    a = fa[j][a];
                    ans = min(ans, g[j][b]);
                    b = fa[j][b];
                }
            }
            ans = min(ans, g[0][a]);
            ans = min(ans, g[0][b]);
        }
        printf("%d\n", ans);
    }
}
int main()
{
    init();
    work();
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-12 09:33:20

Codevs3287 货车运输的相关文章

CODEVS3287货车运输 noip2013day1T3(最大生成树+倍增)

题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路.接下来 m 行每行 3 个整数 x.y.z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路

货车运输

版权声明:本文为博主原创文章,未经博主允许不得转载. 传送门:货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个

AC日记——货车运输 codevs

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A

洛谷P1967 [NOIP2013提高组Day1T2]货车运输

P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y

倍增LCA NOIP2013 货车运输

货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条

3287 货车运输 2013年NOIP全国联赛提高组 40 分

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和

poj1330|bzoj3732|noip2013 货车运输 kruskal+倍增lca

学了一早上倍增,感觉lca还是tarjan好写. poj1330 1 #include <stdio.h> 2 #include <string.h> 3 #include <queue> 4 #include <algorithm> 5 #define DEG 20//2^20 6 #define maxn 10010 7 using namespace std; 8 struct node 9 { 10 int v, next; 11 }a[maxn*2

noip2013货车运输

P1967 货车运输 题目描述 A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入输出格式 输入格式: 输入文件名为 truck.in. 输入文件第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道 路. 接下来 m 行每行 3 个整数 x. y. z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y

3287 货车运输

3287 货车运输 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路.每一条道路对车辆都有重量限制,简称限重.现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物. 输入描述 Input Description 第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城