1368. 燃烧木棍

Description

1368. 燃烧木棍

Solution

根据木棍的长度只有 \(1\) 和 \(\sqrt{2}\) 可知,若两根木棍相交,则一定交在中点。

那我们先将所有点的坐标变成两倍,时间也变成两倍,然后对于长度为 \(\sqrt{2}\) 的木棍,取中点,向两个端点连长度为 \(t\)(因为是\(\frac{2t}{2}\)) 的边。长度为 \(1\) 的木棍就直接将两个端点连起来,长度为 \(2t\)。

然后跑 \(\mathrm{Floyd}\)。枚举每个点作为起点(注意不要枚举新增的中点),求出其到最远的点的燃烧时间。但在这个时间内可能有些边没烧完。所以再遍历所有边,找出需要额外时间最多的边,加入答案。

最后将答案除以 2,因为之前将时间变成了两倍。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 50
#define X 805
#define db double
using namespace std;
struct node
{
    int t,x1,y1,x2,y2,typ;
}edg[N];
struct edge
{
    int x,y,v;
}a[N<<2];
int n,x1,x2,y1,y2,t,cnt,tot,sum1,sum2,id[X][X],dis[N<<2][N<<2];
db ans;
bool bj[N][N];
void add(int x,int y,int z)
{
    a[++tot].x=x;
    a[tot].y=y;
    a[tot].v=z;
    dis[x][y]=z;
}
int main()
{
    freopen("fire.in","r",stdin);
    freopen("fire.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
    {
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&t);
        x1*=2;y1*=2;x2*=2;y2*=2;t*=2;
        x1+=400;x2+=400;y1+=400;y2+=400;
        if (!id[x1][y1]) id[x1][y1]=++cnt;
        if (!id[x2][y2]) id[x2][y2]=++cnt;
        edg[i].t=t;
        edg[i].x1=x1;edg[i].y1=y1;edg[i].x2=x2;edg[i].y2=y2;
        if (x1==x2||y1==y2) edg[i].typ=1;
        else edg[i].typ=2;
        bj[id[x1][y1]][id[x2][y2]]=bj[id[x2][y2]][id[x1][y1]]=true;
    }
    memset(dis,0x3f3f3f3f,sizeof(dis));
    for (int i=1;i<=n;++i)
    {
        x1=edg[i].x1;y1=edg[i].y1;
        x2=edg[i].x2;y2=edg[i].y2;
        t=edg[i].t;
        if (edg[i].typ==1) add(id[x1][y1],id[x2][y2],t),add(id[x2][y2],id[x1][y1],t);
        else
        {
            if (x1>x2) swap(x1,x2),swap(y1,y2);
            if (id[x1][y2]&&id[x2][y1]&&bj[id[x1][y2]][id[x2][y1]])
            {
                int x=(x1+x2)/2,y=(y1+y2)/2;
                if (!id[x][y]) id[x][y]=++cnt;
                add(id[x1][y1],id[x][y],t/2);
                add(id[x][y],id[x1][y1],t/2);
                add(id[x][y],id[x2][y2],t/2);
                add(id[x2][y2],id[x][y],t/2);
            }
            else
            {
                add(id[x1][y1],id[x2][y2],t);
                add(id[x2][y2],id[x1][y1],t);
            }
        }
    }
    for (int i=1;i<=cnt;++i)
        dis[i][i]=0;
    for (int k=1;k<=cnt;++k)
        for (int i=1;i<=cnt;++i)
            for (int j=1;j<=cnt;++j)
                if (i!=j&&i!=k&&j!=k)
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
    ans=2147483647.0;
    for (int i=1;i<=n;++i)
    {
        sum1=sum2=0;
        for (int j=1;j<=cnt;++j)
            sum1=max(sum1,dis[i][j]);
        for (int j=1;j<=tot;++j)
        {
            int x=a[j].x,y=a[j].y,v=a[j].v;
            int c=sum1-dis[i][x]+sum1-dis[i][y];
            if (c>=v) continue;
            sum2=max(sum2,v-c);
        }
        ans=min(ans,(db)((sum1+sum2/2.0)/2.0));
    }
    printf("%.4lf\n",ans);
    return 0;
}
上一篇:acwing-798. 差分矩阵


下一篇:前缀和与差分复习