• [SinGuLaRiTy] 2017-04-08 综合性测试


    【SinGuLaRiTy-1016】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

    对于所有的题目:Time Limit:1s  |  Memory:256 MB

    第一题:路径

    题目描述

    有n个点,m条无向边,有A,B两个人,初始时刻A在点1,B在点2,他们要走到点n去。A每走一条边,要消耗B单位能量,B每走一条边,要消耗E单位能量。如果A,B相伴走,则只消耗P单位的能量。请问A,B走到点n,最少要消耗多少能量?

    输入数据保证1和n,2和n连通。

    输入

    第一行包含整数B,E,P,N和M,所有的整数都不超过40000,N>=3。

    接下来M行,每行两个整数,表示该无向边连接的两个顶点。

    输出

    一个整数,表示最小要消耗的能量。

    样例数据

    样例输入 样例输出
    4 4 5 8 8
    1 4
    2 3
    3 4
    4 7
    2 5
    5 6
    6 8
    7 8
    22

    STD Code

    <BFS>

    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<vector>
    
    #define MAXN 40005
    #define INF 0x3f3f3f3f
    
    using namespace std;
    
    int cost_A,cost_B,cost_AB,num_point,num_edge,ans=INF;
    int va[3][MAXN];
    bool vis[3][MAXN];
    
    struct node
    {
        int x,cnt;
        node(){}
        node(int c,int y)
        {
            x=c,cnt=y;
        }
    };
    
    vector <int> a[MAXN];
    
    void bfs(int x)
    {
        int last=x;
        if(last==3)
            last=num_point;
        queue <node> q;
        q.push(node(last,0));
        vis[x-1][last]=1;
        while(!q.empty())
        {
            node now=q.front();
            q.pop();
            va[x-1][now.x]=now.cnt;
            int sz=a[now.x].size();
            for(int i=0;i<sz;i++)
            {
                if(vis[x-1][a[now.x][i]])
                    continue;
                vis[x-1][a[now.x][i]]=1;
                q.push(node(a[now.x][i],now.cnt+1));
            }
        }
    }
    
    int main()
    {
        scanf("%d%d%d%d%d",&cost_A,&cost_B,&cost_AB,&num_point,&num_edge);
        for(int i=1;i<=num_edge;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            a[x].push_back(y);
            a[y].push_back(x);
        }
        bfs(1);
        bfs(2);
        bfs(3);
        for(int i=1;i<=num_point;i++)
        {
            if(!vis[0][i]||!vis[1][i]||!vis[2][i])
                continue;
            ans=min(ans,va[0][i]*cost_A+va[1][i]*cost_B+va[2][i]*cost_AB);
        }
        printf("%d",ans);
        return 0;
    }

    <SPFA-Sources From G20190812>

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    
    const int INF=0x3f3f3f3f;
    const int MAXN=40010;
    
    using namespace std;
    
    struct node
    {
        int e,next;
    }Link[MAXN*2];
    
    int arr[MAXN],ans1[MAXN],ans2[MAXN],ansn[MAXN];
    int cost_A,cost_B,cost_AB,num_point,num_edge;
    bool vis[MAXN];
    
    queue<int>q;
    
    void Spfa(int r,int fg)
    {
        int s;vis[r]=1;q.push(r);
        while(!q.empty())
        {
            s=q.front();q.pop();vis[s]=1;
            for(int i=arr[s];i;i=Link[i].next)
            {
                if(fg==1)
                    ans1[Link[i].e]=min(ans1[Link[i].e],ans1[s]+1);
                if(fg==2)
                    ans2[Link[i].e]=min(ans2[Link[i].e],ans2[s]+1);
                if(fg==0)
                    ansn[Link[i].e]=min(ansn[Link[i].e],ansn[s]+1);
                if(!vis[Link[i].e])
                {
                    vis[Link[i].e]=1;
                    q.push(Link[i].e);
                }
            }
        }
    }
    
    int main()
    {
        int tmp_a,tmp_b,cnt=0;
        scanf("%d%d%d%d%d",&cost_A,&cost_B,&cost_AB,&num_point,&num_edge);
        for(int i=1;i<=num_edge;i++)
        {
            scanf("%d%d",&tmp_a,&tmp_b);
            Link[++cnt].e=tmp_a;Link[cnt].next=arr[tmp_b];arr[tmp_b]=cnt;
            Link[++cnt].e=tmp_b;Link[cnt].next=arr[tmp_a];arr[tmp_a]=cnt;
        }
        memset(ans1,INF,sizeof(ans1));
        ans1[1]=0;Spfa(1,1);//找1最短路
    
        memset(ans2,INF,sizeof(ans2));
        memset(vis,0,sizeof(vis));
        ans2[2]=0;Spfa(2,2);//找2最短路
    
        memset(ansn,INF,sizeof(ansn));
        memset(vis,0,sizeof(vis));
        ansn[num_point]=0;Spfa(num_point,0);//找n最短路
    
        cnt=INF;
        for(int i=1;i<=num_point;i++)
            cnt=min(cnt,ans1[i]*cost_A+ans2[i]*cost_B+ansn[i]*cost_AB);
        printf("%d
    ",cnt);
        return 0;
    }

    题目分析

    考试时,一看到这道题:“天哪,居然考图论......” 于是卡了半天,决定还是跳过这道题比较好——然而,考完后听说暴力居然可以骗个几十分......

    下面,我们来看看这道题的思路:

    我们应该知道,这道题是一道求最短路的题,只是不能单纯的求最短路而已。事实上,我们在分别对A、B求到n的最短路后,会发现A、B会和的节点不一定在A、B各自的最短路上,因此,我们还要对n求一次最短路(也可以BFS),找到会和的节点,最后再来求出最少消耗的总能量。

    第二题:magic

    题目描述

    小魔仙为了拯救她的好朋友芭比兔,千方百计的弄到了关押芭比兔的迷宫的地图。迷宫的入口在点1处,关押芭比兔的地点在点n处。在迷宫中,小魔仙只能沿着水平方向或竖直方向移动,否则就会碰壁。迷宫中的墙是无形的,幸好地图中已经给出了小魔仙的所有必经地点,她必须严格按照地图中给出的顺序访问这些必经点,才能达到点n处。小魔仙走路的速度很慢,每秒种只能走一个单位距离。但是小魔仙可以施展魔法,这样她可以瞬间跳过其中若干点,时间消耗几乎为0。但是她的魔法最多只能让她跳过k个点(注意:她不能跳过起点和终点,即点1和点n)。她想以最快的速度救出芭比兔,请问她最少需要多少时间。地图的行经路线可能会多次经过同一个坐标。小魔仙跳过的k个点是指在行经路线中的点,如果某个点被跳过多次,则每一次都要消耗魔法。

    输入

    第一行包含N,K.(N<=500,K<=N)接下来N行包含两个整数x,y,表示需要访问的顶点坐标。(-1000<=x<=1000,-1000<=y<=1000)

    输出

    小魔仙最少需要的时间。

    样例数据

    样例输入 样例输出

    5 2

    0 0

    8 3

    1 1

    10 -5

    2 2

    4

    STD Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    
    #define INF 0x3f3f3f3f
    #define MAXN 510
    
    using namespace std;
    
    int n,m;
    int dp[MAXN][MAXN];
    
    struct node
    {
        int x;
        int y;
    };
    node point[MAXN];
    
    int dis(int a,int b)
    {
        return abs(point[a].x-point[b].x)+abs(point[a].y-point[b].y);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&point[i].x,&point[i].y);
        for(int i=2;i<=n;i++)
            for(int j=0;j<=m;j++)
                dp[i][j]=INF;
        for(int i=2;i<=n;i++)
            for(int j=m;j>=0;j--)
                for(int k=i-1;k>=1&&i-k-1<=j;k--)
                    dp[i][j]=min(dp[i][j],dp[k][j-(i-k-1)]+dis(i,k));
        printf("%d",dp[n][m]);
        return 0;
    }

    题目分析

    先说说考试时的思路:由于从一个节点到另一个节点只能水平或竖直着走,于是我天真地以为能通过对每两个节点之间的“某种关系”来计算出在一个区间内每一个节点对前往终点的的“贡献值”,排序后来求出要删除的点......然而,这种计算“贡献值”的方法要考虑的情况实在太多,根本与打表无异,结果当然是WA掉。

    事实上,这是一道DP题,f[i][j]表示前i个节点中用了j次魔法后走的最短距离,最后的目标状态为f[n][m],DP方程式就没有什么好说的了,需要注意的是:由于是求最短距离,因此我们需要在每一次状态转移的时候取最小值(如标程所示),你也可以不在中间取最小值,在最后再通过一次循环来求解:目标状态为min(f[n][x])(0<=x<=m),也就是说,魔法可能不一定会被用完。

    第三题:公路

    题目描述

    有一条单向的高速公路,只有一条车道,有n(1<=n<=100000)辆车在车高速路上行驶。他们的车速可能不同。但因为只有一条车道,所以不存在超车的可能。如果一辆车追上了前车,它就只能减速,与前车以同样的速度行驶,这样它们可以成为一个group。这些汽车的体积可以忽略不计。问经过T单位时间,高速公路上一共有多少个group。(当T时刻时,所有位置相同的汽车称为一个group)。

    输入

    第一行两个整数N,T(1<=T<=1000000000)

    接下来N行,每行包含两个整数,分别表示一辆车的初始位置和初始速度。

    输出

    一个整数,表示T时刻后有多少个group。

    样例数据

    样例输入 样例输出

    5 3

    0 1

    1 2

    2 3

    3 2

    6 1

    3

    STD Code

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    
    #define LL long long
    
    using namespace std;
    
    int n,k,sum;
    
    struct node
    {
        LL  x,l,f;
    };
    
    node a[100010];
    
    bool cmp(node a,node b)
    {
        return a.f<b.f;
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d%I64d",&a[i].x,&a[i].l);
            a[i].f=a[i].x;
            a[i].x+=a[i].l*k;
        }
        sort(a+1,a+1+n,cmp);
        LL  p=a[n].x;
        for(int i=n-1;i>=1;i--)
        {
            if(a[i].x>=p)
                sum++;
            else
                p=a[i].x;
        }
        printf("%d",n-sum);
        return 0;
    }

    题目分析

    考试的时候,把cmp函数的返回值写成了“return a.f<a.f”......居然过了样例......我就呵呵了。

    下面来看看这道题的思路:

    我们先在输入数据时计算出每一辆车的末端点(也就是忽略其他车辆阻碍所能行驶到的最远距离),再按起始点排序。排完序我们就会发现:假设A的起始点比B的起始点小,但是A的末端点比B的末端点大,那就意味着A会超过B,不过这当然不会发生,A会与B“融为一体”。我们来画个图好了:

    如图,有五辆车,我们已经按起始点对它们排了序。此时我们会发现,2号车会阻拦1号车,5号车会阻拦3号、4号车。总结以上规律,我们发现,若从最后一辆车往前扫描,那么我们就需要将第n-i号车与之前终点最近的起到阻碍作用的车的终点经行比较:若仍会被阻拦(像图中的4和5、3和5、1和2),就归为一个group;若不能,即追不上阻拦的车,那么就不能归为一个group。

    Time : 2017-04-08

  • 相关阅读:
    Java Learning (201108025)
    Java Learning (20110808)
    Negative numbers and binary representation
    “this” pointer
    NullPointerException
    Special Swiss Education
    Java Learning (20110802)
    More about Swiss keyboard
    About memory leak
    Application Verifier
  • 原文地址:https://www.cnblogs.com/SinGuLaRiTy2001/p/6681978.html
Copyright © 2020-2023  润新知