2018.9.7南海中学测试T2 (二分答案)

B疫情延迟
Description
由于A 学校生物实验室里那个不负责的数据分析员,实验室的病毒威力被错误估算,导致了可怕的病毒泄漏,现在病毒即将在校园内传播开来。
校园里一共有n 个建筑物,生物实验室总是位于一号建筑物且在0 时刻受到病毒入侵。这n 个建筑物由m 条单向道路相连(也有可能有建筑物被孤立)。每条道路有两个信息:它的长度,它是多少年前修建的。当一个建筑物被病毒入侵,从被入侵的时刻起,病毒会从所有由这个建筑物通向其他建筑物的道路按着这条道路的方向以1 个单位每秒的速度行进。
校长得知这个事情后,决定放弃这个学校逃跑。校长总是位于编号为n 的行政楼,从零时刻开始需要共T 秒来逃出行政楼,且逃出行政楼即视为逃出了这个学校。也就是说,如果病毒入侵行政楼的时间不小于T,则校长能够成功逃离。
有些时候,校长没有足够的时间逃离,因为病毒到达行政楼的时间太快了。
为了让校长能够逃离学校,不得不拆除校园内的一些道路以延缓行政楼的被入侵时间(拆除道路视为在0 时刻被拆的道路全部消失)。当然,如果使得病毒根本无法到达行政楼,也是可以的。
但是,拆除道路会影响学校的历史气息,且破坏程度定义为拆除的道路中最古老的一条的年龄。请求出保证校长能够安全撤离的情况下,最小的破坏程度。
Input
第一行包含三个整数:n, m, T。
接下来m 行,每行描述一条有向道路。每行4 个整数,si, ti, Li, Yi,分别表示这条道路的起点,终点,长度,这条道路的年龄。
Output
如果不需要拆除任何道路,输出一行两个数:-1 和行政楼的被感染时刻(当然这个时刻大于等于T),以空格隔开。
否则输出一行包含一个数:最小的破坏程度。
Sample Input
【样例输入1】
5 5 15
1 2 6 35
2 4 8 40
1 3 6 45
3 4 3 25
4 5 5 50
【样例输入2】
3 2 10
1 2 5 30
2 3 6 50
Sample Output
【样例输出1】
25
【样例输出2】
-1 11
Hint
【样例解释1】
每条边上的黑字对应这条路的长度,红字对应年龄。校长将在第15 秒逃出学校,
如果不拆除任何道路,行政楼将在第14 秒受到入侵。你可以拆除4 到5 的道路,
使得行政楼免于入侵,这样的破坏程度是50。但是最好的方法是拆掉3 到4 之间的道路,这样使得行政楼在第19 秒受到入侵,校长就可以逃离了。
【数据范围】
对于20%的数据,n, m<=10
对于60%的数据,n, m<=100.
对于100%的数据,n<=20000, m<=100000.
数据保证在不拆除任何道路的情况下,从1 号楼到n 号楼一定存在路径。


所以,就要开始说一说读题的重要性了。
一开始我没有看完题目,然后直接就照着数据去试,然后,我把题目理解成了,将所有删掉的路的文化值加起来,保证最后的文化值的和是最小。然而,最后只对了样例emmmmm。

所以,这道题目的题意到底是什么意思呢?
就是有个病毒,从1号楼出发,每秒走一步,要走到n号楼去感染校长。然后校长要离开n号楼,离开n号楼校长就安全了。然后也就是只要1号楼到n号楼的最短路径大于等于校长离开n号楼的时间,校长就安全了。
然后你可以拆掉一些路,每条路都有文化值,你要拆掉一些路,使病毒不能走这条路,所以病毒去n号楼的时间就会变长。然后整个的破坏程度就是你拆的路的最大的文化值,要你求出最小的破坏程度是多少。

我就是看错题,以为破坏程度是拆掉的路的总和,所以在SPFA松弛时就保存最小文化值的边,然后删去。如果删去后校长还是不安全,继续删。然而这样是错的。

看看题目,最终求的只是所有路中的其中一个文化值,因为低于这个最后文化值的道路都是不用的,也就是删去的。所以这样就可以想到,用二分答案

二分答案,将所有边按照文化值排序,每次取中间的文化值,如果这个文化值一下都路都不用,但是病毒能威胁到校长,就找比这个文化值更大的路。如果不能威胁校长,那么再寻找是否有更小的文化值不能威胁校长。所以就这样子二分,最终找出答案就ok了。

现在的我最主要是,没有好好读题。然后我也不知道如果我读懂题目了,能不能想到这道题用二份答案。所以,做的题目还是有点少,遇到一次就总结一次经验吧。

贴上我的代码:

#include<iostream>
#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
const int oo=0x3f3f3f3f;
struct PATH{
    int si,ti,li,yi;
}path[100005];
int n,m,T,pi,min_k,ans,mid,out;
bool vis[20005];
int p[20005];
int last[20005];
int cost[20005];
int nxt[100005];
int to[100005];
int li[100005];
int yi[100005];

void read();
void SPFA();
void work();
bool cmp(PATH i,PATH j)
{
    return i.yi<j.yi;
}

int main()
{
    read();

    int l=1,r=m;
    SPFA();
    if(cost[n]>=T)
    {
        printf("-1 %d",cost[n]);
        return 0;
    } 
    sort(path+1,path+m+1,cmp);
    while(l<=r)
    {
        mid=l+r>>1;
        out=path[mid].yi;
        SPFA();
        if(cost[n]>=T)
          r=mid-1;
        else
          l=mid+1;

    }
    printf("%d",path[l].yi);
    return 0;
}

void SPFA()
{   
    for(int i=1;i<=n;i++)
      cost[i]=oo;
    queue<int> q;
    while(!q.empty())
      q.pop();
    q.push(1);
    vis[1]=true;
    cost[1]=0;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=false;
        int k=p[u];
        while(k>0)
        {
            int v=to[k];
            int lim=li[k];
            if(yi[k]<=out)
              lim=oo;
            if(cost[v]>=cost[u]+lim)
            {
                if(!vis[v])
                {
                    vis[v]=true;
                    q.push(v);
                }
                cost[v]=cost[u]+lim;
            }
            k=nxt[k];
        }
    }
}
void read()
{
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
    scanf("%d%d%d",&n,&m,&T);
    for(int i=1;i<=m;i++)
    {
        int s,t,l,y;
        scanf("%d%d%d%d",&s,&t,&l,&y);
        pi++;
        nxt[pi]=p[s];
        p[s]=pi;
        to[pi]=t;
        li[pi]=l;
        yi[pi]=y;
        path[i].si=s;
        path[i].ti=t;
        path[i].li=l;
        path[i].yi=y;
    }
    li[min_k]=oo;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值