【2018.3.17】模拟赛之四-ssl1864&jzoj1368 燃烧木棒【最短路,Floyd】

正题

链接 需要纪中OJ账号
有n条木棒,长度为1或根号2,给出每根木棒两头的坐标,和燃烧需要的时间。只能从一个木棒的一头开始点火,求燃烧完所有木棒所需要的最短时间。
From jzoj


输入输出(需要自取)

Input

输入文件第一行为一个正整数N,表示组成图形的木棍数目,后面共有N行,每行5个数: X1 Y1 X2 Y2 T,其中(X1, Y1)和(X2, Y2)分别表示木棍两端的坐标,T表示木棍燃烧时间,是指从木棍的某一端点火燃烧到别一端,燃完所需的时间。

Output

输出文件是一个保留4位小数的实数,表示所有木棍完全燃烧的最少时间。

Sample Input

输入1:

1
0 0 1 1 1

输入2:

5
0 0 0 1 1
1 0 0 1 10
0 0 1 0 1
0 0 1 1 1
2 2 1 1 1

输入3:

3
1 1 1 2 10
1 2 2 2 10
1 1 2 2 50

Sample Output

输出1:

1.0000

解释:

从任一端点火都行,燃烧时间都是1

输出2:

3.2500

解释:

在 (0,0)位置点火木棍 1, 3 和 4 将被点燃,燃烧0.5分钟后,木棍2将被从中间点燃向两端燃烧,再过0.5分钟,木棍1, 3, 4 将被完全燃烧,木棍5 将被点燃并在1分钟后燃烧完 (比木棍2早燃完)。   木棍2从中间向两端燃烧0.5分钟以后,变成两小段,每段的燃烧时间是4.5 分钟。但因为此时两小段木棍的另一端也同时被点燃,燃烧速度变成原来的两倍,还需2.25 分钟的燃烧时间, 所以总时间: 1 + 2.25 = 3.25

输出3:

35.0000

解释:

在 (1,2)位置点火, 木棍(1 1, 1 2) 和(1 2, 2 2)将燃烧 10 分钟。. 最后一根木棍在10分钟后从两端被点燃,燃烧时间为25分钟。


解题思路

木棒可能在中间相连的情况只能在中间,所有加入一下中间点就好了。然后用Floyd最短路算出每个点到其他点的距离,不过所有的点烧完不代表木棒被烧完,所有我们需要枚举点开始烧的点,然后计算每个木棒需要燃烧的时间。


代码

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1601][1601],n,x1,x2,x3,y1,y2,y3,m,wn;
bool mid[501];
double dis[501][501],mins,maxs,lon,ans,e[501][501];
int main()
{
    for (int i=0;i<=500;i++)
      for (int j=0;j<=500;j++)
      {
        dis[i][j]=2147483647;
        e[i][j]=2147483647;
      }
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d%lf",&x1,&y1,&x2,&y2,&lon);
        x1+=400;x2+=400;y1+=400;y2+=400;//转换为正数
        x1*=2;x2*=2;x3=(x1+x2)/2;
        y1*=2;y2*=2;y3=(y1+y2)/2;//求中间的坐标
        lon/=2;//分为两条木棍
        if (!a[x1][y1])
        {
            m++;//加入新坐标
            a[x1][y1]=m;//表示该坐标的点编号
        }
        if (!a[x2][y2])
        {
            m++;
            a[x2][y2]=m;
        }
        if (!a[x3][y3])
        {
            m++;
            a[x3][y3]=m;
            mid[m]=true;
        }
        dis[a[x1][y1]][a[x3][y3]]=lon;
        dis[a[x3][y3]][a[x1][y1]]=lon;
        dis[a[x2][y2]][a[x3][y3]]=lon;
        dis[a[x3][y3]][a[x2][y2]]=lon;//记录
        e[a[x1][y1]][a[x3][y3]]=lon;
        e[a[x3][y3]][a[x1][y1]]=lon;
        e[a[x2][y2]][a[x3][y3]]=lon;
        e[a[x3][y3]][a[x2][y2]]=lon;
    }
    for (int k=1;k<=m;k++)
      for (int i=1;i<=m;i++)
        for (int j=1;j<=m;j++)
        {
            if (dis[i][k]<2147483647 && dis[k][j]<2147483647)
            dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);//计算最短路
        }
    mins=2147483647;
    for (int k=1;k<=m;k++)
    {
      if(mid[k]) continue; //排除在中间点
      ans=0;
      for (int i=1;i<=m;i++) ans=max(dis[k][i],ans);//取所有点烧完的所需时间
      for (int i=1;i<=m;i++)
        for (int j=i+1;j<=m;j++)
        {
          if(e[i][j]<2147483647)
          if (dis[k][i]<e[i][j]+dis[k][j] && dis[k][j]<dis[k][i]+dis[i][j])//是否相接
          {
            ans=max(ans,max(dis[k][i],dis[k][j])
              +(e[i][j]-max(dis[k][i],dis[k][j])
              +min(dis[k][i],dis[k][j]))/2.0);
              //计算该木棒燃烧时间取最大值
          }
        }
      mins=min(ans,mins);//取最少的时间
    }
    printf("%.4lf",mins);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值