正题
链接 需要纪中OJ账号
有n条木棒,长度为1或根号2,给出每根木棒两头的坐标,和燃烧需要的时间。只能从一个木棒的一头开始点火,求燃烧完所有木棒所需要的最短时间。
输入输出(需要自取)
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);
}