【原创】2018.07.04 测试 /路径魔法公路//

2018.07.04测试

说在前边

yeah我回来了(虽然过几天要走了)
我105的C币怎么只有15个了啊
樱樱樱
樱樱樱

路径

时间限制: 1 Sec 内存限制: 128 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

分析

考试的时候没有任何头绪。
我不看足球了!!!!!
根本没有睡醒好咩?!!?!??!

如果这么看就好了。
两人分别从1,2点出发,在图上某一点会合
会合前,两人每走一条边会有不同的能量消耗,会合后,两人一起,能量消耗又会变化。
而求最小消耗的话,会合之前,两人都要走最短路径,会合之后,两人也要走最短路径。
所以在哪个点会合呢?
枚举一下就Ok了。
判断的方法:用
1到这里的最短距离*A的消耗+2到这里的最短距离*B的消耗+n到这里的最短距离*AB合体后的消耗取最小值即可。
这样的话,边权都是1,可以开开心心地跑bfs了。

代码

#include<cmath>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;

void Read(int &p)
{
    p=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') 
        p=p*10+c-'0',c=getchar();
}

const int MX=40000+4;
const int XM=80000+4;
int n,m,a,b,ab,p,q;
int to[XM],nxt[XM],head[MX],cnt,dis[3][MX];

void addedge(int p,int q)
{
    to[++cnt]=q,nxt[cnt]=head[p],head[p]=cnt;
    to[++cnt]=p,nxt[cnt]=head[q],head[q]=cnt;
}

queue<int>Q;
bool vis[MX];
void bfs(int grandorder)
{
    memset(vis,0,sizeof vis);
    while(!Q.empty()) Q.pop();

    int s=(grandorder==2)?n:grandorder+1;
    dis[grandorder][s]=0, Q.push(s), vis[s]=1;
    while(!Q.empty())
    {
        int h=Q.front(); Q.pop();
        for(int i=head[h];i;i=nxt[i])
            if(!vis[to[i]]) 
                Q.push(to[i]),vis[to[i]]=1,
                dis[grandorder][to[i]]=dis[grandorder][h]+1;
    }
}

int main()
{
    Read(a); Read(b); Read(ab);Read(n); Read(m); 
    for(int i=1;i<=m;i++)
        Read(p),Read(q),addedge(p,q);
    memset(dis,120,sizeof dis);
    bfs(0); bfs(1); bfs(2);
    int ans=2147483647;
    for(int i=1;i<=n;i++) ans=min(ans,dis[0][i]*a+dis[1][i]*b+dis[2][i]*ab);
    printf("%d\n",ans);
}

闲得……dant……发慌码了一个手动队列……
(其实是我某处做错了怀疑是queue的问题樱樱樱)

#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

void Read(int &p)
{
    p=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') 
        p=p*10+c-'0',c=getchar();
}

const int MX=40000+4;
const int XM=80000+4;
int n,m,a,b,ab,p,q;
int to[XM],nxt[XM],head[MX],cnt,dis[3][MX];

void addedge(int p,int q)
{
    to[++cnt]=q,nxt[cnt]=head[p],head[p]=cnt;
    to[++cnt]=p,nxt[cnt]=head[q],head[q]=cnt;
}

int fakeq[MX],he,ta;
bool vis[MX];
void bfs(int grandorder)
{
    memset(vis,0,sizeof vis);
    he=ta=0;

    int s=(grandorder==2)?n:grandorder+1;
    dis[grandorder][s]=0,fakeq[ta++]=s,vis[s]=1;
    while(he<ta)
    {
        int h=fakeq[he++];
        for(int i=head[h];i;i=nxt[i])
            if(!vis[to[i]]) 
                fakeq[ta++]=to[i],
                dis[grandorder][to[i]]=dis[grandorder][h]+1,
                vis[to[i]]=1;
    }
}

int main()
{
    Read(a); Read(b); Read(ab);Read(n); Read(m); 
    for(int i=1;i<=m;i++)
        Read(p),Read(q),addedge(p,q);
    memset(dis,120,sizeof dis);
    bfs(0); bfs(1); bfs(2);
    int ans=2147483647;
    for(int i=1;i<=n;i++) ans=min(ans,dis[0][i]*a+dis[1][i]*b+dis[2][i]*ab);
    printf("%d\n",ans);
}

魔法(magic)

题目描述

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

输入

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

输出

小魔仙最少需要的时间。

输入样例

5 2
0 0
8 3
1 1
10 -5
2 2

输出样例

4

样例解释

小魔仙可以跳过(8,3),(10,-5)。

数据规模与约定(手动加的)

N,K不超过500

分析

不知道为什么一眼就看出来是一个选或不选的01背包问题^-^。
考试的时候就分析了这么个方程:

dp[i][j]表示到第i个点的时候用了j次魔法
如果到这里来的时候没用魔法
则dp[i][j]=dp[i-1][j]+dis[i][i-1]
如果从上一个点到这里来时用了魔法
则dp[i][j]=dp[i-2][j-1]+dis[i][i-2]

只得了12分的说(╥╯^╰╥)

为什么错了呢?
“如果从上一个点到这里来时用了魔法”
我好像不知道有多段跳似的,,,

如果有8个点,6个魔法,我们不可以直接刷刷刷刷刷刷跳到终点么?这样就是上六个点
因此,我们应该枚举一下到底是上几个点跳过来的。
具体的方程请详见代码。

代码

#include<cmath>
#include<cstdio>
#include<cstring>

void Read(int &p)
{
    p=0;
    int f=1;
    char c=getchar();
    while(c<'0'||c>'9') 
    {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') 
        p=p*10+c-'0',c=getchar();
    p*=f;
}

const int MX=500+4;
int n,k,x[MX],y[MX],dis[MX][MX],dp[MX][MX];
int Xbs(int i){return i>=0?i:-i;}
int mn(int a,int b){return a<b?a:b;}

int main()
{
    Read(n); Read(k);
    for(int i=1;i<=n;i++)
        Read(x[i]),Read(y[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            dis[i][j]=Xbs(x[i]-x[j])+Xbs(y[i]-y[j]);
    memset(dp,120,sizeof dp);   
    for(int j=0;j<=k;j++)       dp[1][j]=0;
    for(int i=2;i<=n;i++)
        for(int j=k;j>=0;j--)
            for(int l=0;l<=j;l++)
                dp[i][j]=mn(dp[i][j],dp[i-l-1][j-l]+dis[i][i-1-l]);
    int ans=2147483647;
    for(int j=0;j<=k;j++) ans=mn(ans,dp[n][j]);
    printf("%d\n",ans);
}

公路

时间限制: 1 Sec 内存限制: 128 MB

题目描述

有一条单向的高速公路,只有一条车道,有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

分析

一年多以前做过一遍,考试一拿到就想出来了……
……
……
……
一种不一样的方法。

题意比较好懂,想象一下那个场景就OK了。
这里写图片描述
追上了但因为路……窄而只能合体一起走,就成了一个group,大家都变得慢悠悠
所以
我们只需要看哪些本来落后的车追上了前面的车即可
所以:

因为输出不会按顺序给你谁先谁落后,我们要先按起始位置排序
怎样知道能否追上?
1、相同时间比路程:算出两辆车T时刻时所处位置(如果没有group这种设定)
2、比时间:算出追及的时间看在不在T时刻内
然后就从1开始,看1能不能追上2,2能不能追上3……

这么想的话,恭喜您获得了6分!(坏笑)

这里写图片描述
如果是这样你就要被扣很多分了哟,你还有比完2和3之后,再来比较1和2

怎么解决?
因为无论是谁先追上谁,反正最终是追上了,而group的领头羊无论如何都会被它身后离它最近的车追上
所以倒着搞就没问题了

代码

方法一:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define lol long long

void Read(lol &p)
{
    p=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') 
        p=p*10+c-'0',c=getchar();
}

const int MX=100000+5;
lol T,n,groups;

struct cars
{
    lol v,p,final;
    void R()
    {
        Read(p); Read(v); final=p+v*T;
    }
    bool operator < (const cars &a) const
    {
        return p>a.p;
    }
}c[MX];

int main()
{
    Read(n); Read(T); groups=n;
    for(lol i=1;i<=n;i++) c[i].R();
    sort(c+1,c+1+n);
    lol locating=c[1].final;
    for(lol i=2;i<=n;i++)
        if(locating<=c[i].final) groups--;
        else locating=c[i].final;
    cout<<groups<<endl;
}
方法二:

羞)我说的一年前的那种不同的方法

#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=102017;
void Read(LL & p)
{
    p=0;
    char c=getchar();
    while(c<'0' or c>'9') c=getchar();
    while(c>='0' and c<='9')
        p=p*10+c-'0',c=getchar();
}
struct Epic
{
    LL v,s;
    bool operator < (const Epic & p) const
    {
        return s<p.s;
    }
}car[maxn];
LL T,n,ans;
LL took(LL i,LL j)
{
    return (car[j].s-car[i].s)/(car[i].v-car[j].v);
}
int main ()
{
    Read(n); Read(T);
    ans=n;
    for(LL i=1;i<=n;i++)
        Read(car[i].s),Read(car[i].v); 
    sort(car+1,car+1+n);
    for(LL i=1;i<=n;i++)
        for(LL j=i+1;j<=n;j++)
            if(car[i].s==car[j].s) 
            {
                ans--;
                break;
            }
            else if(car[i].v>car[j].v)
            {
                if(took(i,j)<=T) 
                {
                    ans--;
                    break;
                }
            }
    printf("%lld\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值