NOIP 2013 货车运输 题解过程

今天做了NOIP 2013 的货车运输。 
刚开始一看题目。

**题目描述 Description 
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。 
输入描述 Input Description 
第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。 
接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。 
接下来一行有一个整数 q,表示有 q 辆货车需要运货。 
接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。 
输出描述 Output Description 
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。 
样例输入 Sample Input 
4 3 
1 2 4 
2 3 3 
3 1 1 

1 3 
1 4 
1 3 
样例输出 Sample Output 

-1 

数据范围及提示 Data Size & Hint 
对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000; 
对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000; 
对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

首先想到的是并查集维护的最大生成树。 
然后对于每一次询问,一条边一条边的加,直到加到某一条边后能导致所询问的两点能够联通;因为已经按照边权从小到大排序过,所以现在加的边肯定是通路里面权值最小的边。输出此边即可。

不难看出,这种方法是正确的,但是对于后40%的数据会TLE。 
(后面有60分的代码,这种做法比较好写,适合骗分) 
所以,我们只进行一次最大生成树,之后用倍增的方法求每次询问的两点的LCA 查找过程中维护道路上的最小值,最后输出即可。复杂度为O(mlogn)的。

60分代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
using namespace std;
int n,m,s,ti,c;
int h[N],v[N],next[N],p=0,d[N],f[N];
inline int get_num()
{   
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');   
if (c == '-') flag = true;  
else num = c - '0'; 
while (isdigit(c = getchar()))      
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
struct re
{
    int x,y,bh,qz;
} q[N];
void mem()
{
    for(int i=1;i<=N;i++)
    {
        f[i]=i;
    }
}
int find(int x)
{
    return f[x]==x ? x:f[x]=find(f[x]);
}
void add(int a,int b,int c)
{
    p++;
    q[p].x=a;
    q[p].y=b;
    q[p].bh=p;
    q[p].qz=c;
}
bool cmp(const struct re a,const struct re b)
{
    return a.qz>b.qz;
}
int main()
{
    n=get_num();
    m=get_num();
    for(int i=1;i<=m;i++)
    {
        int qqq,w,e;
        qqq=get_num();w=get_num();e=get_num();
        add(qqq,w,e);
        add(w,qqq,e);
    }
    sort(q+1,q+p+1,cmp);
    /*for(int i=1;i<=m*2;i++)
    {
        cout<<q[i].qz<<" ";
    }*/
c=  get_num();
    for(int i=1;i<=c;i++)
    {
        int qq,w,ans=2147483647;
        bool vv=0;
        qq=get_num();w=get_num();
        mem();
        for(int j=1;j<=p;j++)
        {
            if(find(q[j].x)!=find(q[j].y))
            {
                f[f[q[j].x]]=f[q[j].y];
                //ans=min(ans,q[j].qz);
            }
            if(find(qq)==find(w))
            {
                printf("%d\n",q[j].qz);
                vv=1;
                break;
            }
        }
        if(!vv)
        {
            printf("-1\n");
        }
    }
    return 0;
}


满分LCA 做法:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<string>
#include<bitset>
#include<iomanip>
#include<deque>
#define INF 1000000000
#define fi first
#define se second
#define N 100005
#define P 1000000007
#define debug(x) cerr<<#x<<"="<<x<<endl
#define MP(x,y) make_pair(x,y)
using namespace std;
int n,m,s,ti,c;
int h[N],v[N],next[N],p=0,d[N],f[N],w[N],l[N],j[N][15],ww[N][15],deep[N];
bool vv[N];
inline int get_num()
{   
int num = 0;
char c;
bool flag = false;
while ((c = getchar()) == ' ' || c == '\n' || c == '\r');   
if (c == '-') flag = true;  
else num = c - '0'; 
while (isdigit(c = getchar()))      
num = num * 10 + c - '0';
return (flag ? -1 : 1) * num;
}
struct re
{
    int x,y,bh,qz;
} q[N];
int find(int x)
{
    return f[x]==x ? x:f[x]=find(f[x]);
}
void add(int a,int b,int c)
{
    p++;
    v[p]=b;
    w[p]=c;
    next[p]=h[a];
    h[a]=p;
    l[p]=a;
}
void addd(int a,int b,int c)
{
    p++;
    q[p].x=a;
    q[p].y=b;
    q[p].bh=p;
    q[p].qz=c;
}
bool cmp(const struct re a,const struct re b)
{
    return a.qz>b.qz;
}
void dfs(int x,int s)
{
    deep[x]=s;
    for(int i=1;(1<<i)<s;i++)
    {
        j[x][i]=j[j[x][i-1]][i-1];
        ww[x][i]=min(ww[x][i-1],ww[j[x][i-1]][i-1]);
        //cout<<x<<" "<<i<<" :"<<ww[x][i]<<endl; 
    }
    int p=h[x];
    while(p)
    {
        if(vv[v[p]])
        {
            p=next[p];
            continue;
        }
        vv[v[p]]=1;
        j[v[p]][0]=x;
        ww[v[p]][0]=w[p];
        dfs(v[p],s+1);

    }
    return;
}
int just_doit(int x,int y)
{
    int ans=2147483647;
    if(deep[y]>deep[x])
    {
        int tt=x;
        x=y;
        y=tt;
    }
    for(int i=15;i>=0;i--)
    {
        if(deep[x]-(1<<i)>=deep[y])
        {
            ans=min(ans,ww[x][i]);
            x=j[x][i];
        }
    }
    if(x==y)
    {
        return ans;
    } 
    for(int i=15;i>=0;i--)
    {
        if(deep[x]-(1<<i)>=1&&j[x][i]!=j[y][i])
        {
            ans=min(ans,ww[x][i]);
            ans=min(ans,ww[y][i]);
            x=j[x][i];
            y=j[y][i];
        }
    }
    ans=min(ans,ww[x][0]);
    ans=min(ans,ww[y][0]);
    return ans;
}
int main()
{
    n=get_num();
    m=get_num();
    for(int i=1;i<=m;i++)
    {
        int qqq,w,e;
        qqq=get_num();w=get_num();e=get_num();
        addd(qqq,w,e);
        addd(w,qqq,e);
    }
    sort(q+1,q+p+1,cmp);
    for(int i=1;i<=n;i++) f[i]=i;
    int k=0;p=0;
    for(int i=1;i<=m*2;i++)
    {
        int a,b;
        a=q[i].x;
        b=q[i].y;
        if(find(a)!=find(b))
        {
            add(a,b,q[i].qz);
            add(b,a,q[i].qz);
            f[find(a)]=find(f[b]);
            //cout<<a<<" "<<b<<"\n";
            k++;
        }
        if(k==n-1)
        break;
    }
    dfs(1,1);
    c=get_num();
    //cout<<ww[5][1]<<" &&&\n";
    for(int i=1;i<=c;i++)
    {
        int qq,w,ans=0;
        qq=get_num();w=get_num();
        if(find(qq)!=find(w))
        {
            cout<<-1<<"\n";
            continue;
        }
        ans=just_doit(qq,w);
        cout<<ans<<"\n";
    }
    return 0;
}


噫。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
noip2013普及组初赛是全国信息学奥林匹克联赛的一场选拔赛。该比赛旨在选拔初学者,对编程和算法有一定基础的学生,通过比赛形式来考察他们的知识水平和解题能力。 比赛题目通常会涉及各个领域的算法和数据结构,如图论、动态规划、数论等。题目难度逐步增加,从简单的输出结果,到复杂的程序设计与代码实现,考察选手的逻辑思维和编程能力。 参赛选手需要通过自己的思考和编程实现来解决题目,同时时间也是一个重要因素。比赛中,选手需要在规定的时间内独立完成所有题目,对于复杂的题目需要迅速想出解题思路并进行编码。因此,在比赛中,选手的临场发挥和解题速度也是需要考虑的因素。 noip2013普及组初赛的结果将作为选拔阶段的一个重要依据,选出表现出色的选手进入到更高阶段的比赛,对于他们来说,这是一次展示自己实力的机会。 此外,noip2013普及组初赛,也给了参赛选手一个交流的平台。选手们可以通过比赛结交同好,相互切磋,共同进步。同时,比赛结束后,还有详细的解题分析和讲解,有助于参赛选手对自己在比赛中的不足进行反思与改进。 总之,noip2013普及组初赛是一个考察学生编程和算法能力的选拔赛,通过比赛的形式来选拔出优秀的选手。这对于参赛选手来说,是一次展示自己才华的机会,也是一个展示自己实力和提高自己能力的平台。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值