【SCOI2003】【BZOJ1092】蜘蛛难题

Description

有一堆管道,还有一个蜘蛛Willy,如下图所示。所有管道的是上端开口,下端封底,直径都是1cm,连接两个管道的连接容量无限,但体积可以忽略不计。
这里写图片描述

在第一个管道上方有一个水源,从中有水不断往下流,速度为每秒0.25 cm3。由于管道横截面积为0.25 cm3,所以单给一个管道注水时水面每秒上升1cm。根据物理知识,在前2秒中,水注如左边的管道底部,第3~5秒时注入右边的管道,第6~9秒同时注入两个管道(虽然流量不变,但是由于同时给两个管道注水,因此水面上升的速度仅为每秒0.5cm),接触到蜘蛛。 给出管道和管道之间连接的位置,以及蜘蛛Willy的位置,求水面接触到Willy的时间。假设蜘蛛的实际位置比给出的略高一点,因此如果蜘蛛在左边管道的n=4的位置,答案应该是5秒。因为前两秒后水面虽然看起来接触到了Willy,但实际上比Willy略低一点。

Input

所有位置都用有序数对(x, y)表示,其中y坐标从上到下逐渐增大;x坐标从左到右逐渐增大,因此左上角的坐标为(0,0),其他所有坐标值为0到100之间的整数。输入第一行为一个整数p(1<=p<=20),表示管道的数目;以下p行,每行用x, y, h三个整数描述一根管道。(x,y)为管道左上角坐标;h为管道高度(1<=h<=20)。以下一行为一个整数L(0<=L<=50),为连接的个数。以下L行每行用三个整数x, y, d描述一个连接,(x,y)为左端点的坐标,d为连接的长度(1<=d<=20)。最后一行为两个整数a, b,表示Willy在管道a的y坐标为b的位置。管道按照在文件中出现的顺序编号为1,2,3…p 以下为一些假设: 水源总是在第一根管道的正上方 连接不会穿越管道 任意两个连接的y坐标都不相同 任意两个管道的左上角的x坐标都不相同 任意连接的两个端点都在管道上(不会出现悬空的情形)

Output

仅一个整数,为水面接触到Willy的时间。如果水面无法接触到Willy,输出-1。

Sample Input

2

2 0 6

5 1 6

1

3 4 2

2 2
Sample Output

9
HINT

该样例对应题目中的例子。

Source

考虑直接按注水时间来模拟
物理题?数学题?
感觉不符合连通器原理TAT

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 30
#define MAXM 110
using namespace std;
int n,m,S,T,maxn,ans,top;
struct pipe
{
    int x,y,h,v;
}s[MAXN];
int find(int x) {for (int i=1;i<=n;i++) if (s[i].x==x)  return i;return 0;}
struct edge
{
    int to,w;
    edge *next;
}e[MAXM<<1],*prev[MAXN];
void insert(int u,int v,int w)  {e[++top].to=v;e[top].next=prev[u];prev[u]=&e[top];e[top].w=w;}
int main()
{
    scanf("%d",&n);int x,y,w,t1,t2;
    for (int i=1;i<=n;i++)  scanf("%d%d%d",&s[i].x,&s[i].y,&s[i].h),s[i].h+=s[i].y;
    s[1].v=1;
    scanf("%d",&m);
    for (int i=1;i<=m;i++)  scanf("%d%d%d",&x,&y,&w),t1=find(x-1),t2=find(x+w),insert(t1,t2,y),insert(t2,t1,y);
    scanf("%d%d",&S,&T);
    while (1)
    {
        for (x=1;x;)
        {
            x=0;
            for (int i=1;i<=n;i++)
                if (s[i].v)
                for (edge *t=prev[i];t;t=t->next)
                    if (s[i].h<=t->w&&!s[t->to].v)  s[t->to].v=x=1;
        }
        maxn=0;
        for (int i=1;i<=n;i++)  if (s[i].v) maxn=max(maxn,s[i].h);
        if (s[S].v&&maxn==T)    {printf("%d\n",ans);return 0;}
        for (int i=1;i<=n;i++)
            if (s[i].v&&s[i].y==s[i].h&&s[i].y==maxn)   {puts("-1");return 0;}
        for (int i=1;i<=n;i++)
            if (s[i].v&&s[i].h==maxn)   s[i].h--,ans++;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值