SSL P1864 燃烧木棍

目录:

题目:

燃烧木棍题目

题意:

给出我们一个木棍图,求将其全部燃烧完至少要多久时间。

分析:

这道题目,难度肯定是有的,所以这就需要我们理清思路,且要非常明了,下面请让小编带你走进思维的殿堂。
首先我们可以想到的就是最短路,而在这题中,使用 Floyd 算法会比 Dij 方便很多,且不需我们去做任何多余的处理,所以在这点上小编就不多讲了。
其次,也是难点,就是我们要如何去计算他们全燃烧完的时间。
求出从某个点到其它点的最短时间以后,余下的问题是检查每一边是否完全燃烧。如果没有完全燃烧,求出剩余边燃烧所需最长时间。
对于燃烧时间为L的木棍,它的两端被点燃的时刻为T1和T2,如果T1 = T2+L 或者是 T2 = T1+L,那么燃烧到T1 和 T2 的最大时刻,这根木棍己经完全燃烧。
如果T1与T2之间的时间差不等于L,那么就说明火是从不同的路径燃烧到这根木棍的两端。火将从两端向中间燃烧,并在木棍内的某个点燃完,在简单情况中,如果是从两端同时点燃,燃烧时间为L/2。更一般地,如果T1与T2不等,我们设一端是从0时刻点燃,另一端是从T时刻点燃,那么这根木棍的燃烧时间为T+(L-T)/2

AC后感想:

在做的过程中,几度想哭,但在抠标经过讲解后,再冷静下来,重新打了一遍后,就AC了。只能说此题考查选手用图解决问题的能力,并且此题不能简单的套用 Floyed 算法,需要选手在解决问题中灵活运用经典算法。

代码:

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<iostream>
#define r(i,a,b) for(int i=a;i<=b;i++)
#define LL long long
using namespace std;
inline LL read()
{
    LL a=0,f=1;char s=getchar();
    while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
    while(s>='0'&&s<='9') {a=a*10+s-'0';s=getchar();}
    return a*f;
}
int n,m;
double ans=99999999,cc;
double fmax(double x,double y){return x>y?x:y;}
double fmin(double x,double y){return x<y?x:y;}
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
struct node1
{
    int x1,y1,x2,y2,t;
}f[45];//读入数组 
struct node2
{
    int x,y;
}v[101];//边 
int w[101][101],dis[101][101];//燃烧时间以及最短路 
int find(int x,int y)
{
    r(i,1,m)//判断之前是否有出现过 
     if(v[i].x==x&&v[i].y==y)
      return i; 
    m++;//边数+1 
    v[m].x=x;
    v[m].y=y;
    r(i,1,m-1)//初始化w 
      w[i][m]=w[m][i]=99999999;
    w[m][m]=0;
    return m;
}
void gt(int x1,int y1,int x2,int y2,int t)//构图 
{
    int x=find(x1,y1);
    int y=find(x2,y2);
    w[x][y]=w[y][x]=t; 
}
void fz()//将w复制给dis 
{
    r(i,0,100)
     r(j,0,100)
      dis[i][j]=w[i][j];
}
void floyed()//最短路 
{
    r(k,1,m)
     r(i,1,m)if(dis[i][k]<99999999)
      r(j,1,m)if(dis[k][j]<99999999)
       dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
double fire(int k)//燃烧——重头戏!!! 
{
    double now=0,s=0;
    r(i,1,m)
     if(dis[k][i]>now) now=dis[k][i];//求最慢的 
    r(i,1,m-1)
     r(j,i+1,m)
      if(w[i][j]<99999999)//如果有连通 
       if(dis[k][i]<dis[k][j]+w[i][j]&&dis[k][j]<dis[k][i]+w[i][j])
       //如果两端都会燃烧 
        if(dis[k][i]<dis[k][j])//求最慢的,用公式 
         now=fmax(now,dis[k][j]+(w[i][j]-(dis[k][j]-dis[k][i]))/2.0);
        else
         now=fmax(now,dis[k][i]+(w[i][j]-(dis[k][i]-dis[k][j]))/2.0);
    return now;
}
int main()
{
    n=read();
    r(i,1,n)
     f[i].x1=read(),f[i].y1=read(),f[i].x2=read(),f[i].y2=read(),f[i].t=read();
    r(i,1,n)
     {
        //*2和+,都是为了保证点的唯一性 
        gt(f[i].x1*2,f[i].y1*2,f[i].x1+f[i].x2,f[i].y1+f[i].y2,f[i].t);
        gt(f[i].x1+f[i].x2,f[i].y1+f[i].y2,f[i].x2*2,f[i].y2*2,f[i].t);
     }
    fz();
    floyed();
    r(i,1,m)
     if(!(v[i].x&1)&&!(v[i].y&1))//时间优化:只看其中一点
     //ps:我们之前在gt*2了,所以肯定是偶数 
      ans=fmin(ans,fire(i));
    printf("%0.4lf",ans/2);//我们在算点时*2,所以输出时就/2 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值