UOJ Logo zhouzixuan的博客

博客

bzoj 1092: [SCOI2003]蜘蛛难题

2015-12-17 14:10:04 By zhouzixuan
【题目大意】:
    有一堆管道,还有一个蜘蛛Willy,如下图所示。所有管道的是上端开口,下端封底,直径都是1cm,连接两个管道的连接容量无限,但体积可以忽略不计。

    在第一个管道上方有一个水源,从中有水不断往下流,速度为每秒0.25 cm3。由于管道横截面积为0.25 cm3,所以单给一个管道注水时水面每秒上升1cm。根据物理知识,在前2秒中,水注如左边的管道底部,第3~5秒时注入右边的管道,第6~9秒同时注入两个管道(虽然流量不变,但是由于同时给两个管道注水,因此水面上升的速度仅为每秒0.5cm),接触到蜘蛛。 给出管道和管道之间连接的位置,以及蜘蛛Willy的位置,求水面接触到Willy的时间。假设蜘蛛的实际位置比给出的略高一点,因此如果蜘蛛在左边管道的n=4的位置,答案应该是5秒。因为前两秒后水面虽然看起来接触到了Willy,但实际上比Willy略低一点。
【题目解法】:
    不明白为啥这么少人AC,弄得我还以为是神题呢TAT
    按照时间模拟显然
    由于所有坐标都是整数,因此水面只有在上升1cm后才有可能碰到蜘蛛,又因为每次有相同高度并且联通的管道每秒钟的数量是平分的,因此我们只需要每次找到最低的若干个相连(必须还有与水源所在管道相连)管道,同时注入1cm水即可
    所以我们开一个数组记录每个管道在这一次灌水中是否能被灌入
    我们从上一次已经灌了水的管道开始bfs,每次bfs与之相连的管道,判断水的高度是否漫过了连接处,如果是则把这个管道标记一下,然后加入队列继续bfs即可
    对于找到的管道,每次找最低的,然后做以下讨论
    1.蜘蛛所在的管道最低并且已经碰到了蜘蛛,输出此时的时间即可,否则跳转2
    2.最低的管道已经满处了管道口,之后的水会源源不断的流到外面,因此水面都不可能在长高,输出无解,否则跳转3
    3.给所有最低的水面同时+1,然后时间相应加上若干即可
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=105;
const int INF=32083208;
struct edge {int x,y,next;} b[N];
struct point {int x,y,h;} c[N],pos;
int n,m,a[N],tot,ans,q[N]; bool v[N];
inline long long getint()
{
    long long x=0; char c=getchar(); bool flag=false;
    while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
    if (c=='-') flag=true,c=getchar();
    while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
    if (flag) return -x; else return x;
}
inline int find(int x)
{
    for (int i=1; i<=n; i++) if (x==c[i].x) return i;
    return 0;
}
inline void addedge(int x,int y,int z)
{
    ++tot; b[tot].x=y; b[tot].y=z; b[tot].next=a[x]; a[x]=tot;
    ++tot; b[tot].x=x; b[tot].y=z; b[tot].next=a[y]; a[y]=tot;
}
void init()
{
    n=getint(); ans=0; tot=0; memset(a,0,sizeof(a));
    for (int i=1; i<=n; i++) c[i].x=getint(),c[i].y=getint(),c[i].h=c[i].y+getint(); m=getint();
    for (int i=1; i<=m; i++)
    {
        int x=getint(),y=getint(),d=getint();
        addedge(find(x-1),find(x+d),y);
    }
    pos.x=getint(); pos.y=getint();
}
void bfs()
{
    int head=0,tail=0;
    for (int i=1; i<=n; i++) if (v[i]) q[++tail]=i;
    while (head<tail)
    {
        int k=q[++head];
        for (int p=a[k];p;p=b[p].next)
        {
            int pp=b[p].x; if (v[pp]) continue;
            if (c[k].h<=b[p].y) v[pp]=true,q[++tail]=pp;
        }
    }
}
void solve()
{
    memset(v,false,sizeof(v)); v[1]=true;
    while (true)
    {
        bfs(); int maxh=-INF;
        for (int i=1; i<=n; i++) if (v[i]) maxh=max(maxh,c[i].h);
        if ((v[pos.x])&&(c[pos.x].h==maxh)&&(c[pos.x].h==pos.y)) {printf("%d\n",ans); return;}
        for (int i=1; i<=n; i++) if ((v[i])&&(c[i].h==maxh)&&(c[i].h==c[i].y)) {printf("-1\n"); return;}
        for (int i=1; i<=n; i++) if ((v[i])&&(c[i].h==maxh)) c[i].h--,ans++;
    }
}
int main()
{
    init();
    solve();
    return 0;
}

评论

暂无评论

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。