Problem B. Rain Google APAC 2017 University Test Round A

这一题最初算法错了,竟然过了小数据,然后大数据一直WA,debug了好几天T_T。

最开始的想法是把非边界的点按照高度排序。从高度最低的点开始BFS。如果当前点所在的平面(同样高度的,包含当前点的连通平面)可以积水,就把该平面的高度更改为积水高度(积水区域border的最低高度)。

然而我更改过高度就没去管那些点了=。=实际上,被更改高度的点可能还没有被BFS,可是那些点和其他点高度大小关系已经变了。所以按照之前的次序BFS就不是先考虑高度最低的点了。e.g., 五个相邻的点原先为5 3 2 1 5,更改后为5 3 2 4 5,如果BFS还是从倒数第二个的点开始,那么因为2<4,就会认为无法积水。积水过程是5 3 3 4 5 -> 5 4 4 4 5。实际上如果先从2 BFS,仍然可以积水。积水过程是5 3 3 4 5 -> 5 4 4 4 5 -> 5 5 5 5 5。

正解是维护一个优先队列,这样每次BFS一个点之后都会将所有点按照更改后的高度高度重新排序。另外从优先队列pop元素之后,如果是更改之前的值,直接ignore。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<vector>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<stack>
#include<queue>
#include<ctype.h>
#include<map>
#include<time.h>
#include<set>
#include<bitset>
#include<sstream>
using namespace std;
//Google APAC2017 Round A Problem B. Rain

const int maxn=60;
int T;
int R;
int C;
int dx[]={0,-1,0,1};
int dy[]={-1,0,1,0};
int mp[maxn][maxn];
bool vis[maxn][maxn];
int ans;
class node
{
public:
    int x;
    int y;
    int height;
public:
    node()
    {
        x=0;
        y=0;
        height=0;
    }
    node(int x0,int y0,int h)
    {
        x=x0;
        y=y0;
        height=h;
    }
    bool operator < (node b) const
    {
        if(height==b.height)
        {
            if(x==b.x)
            {
                return y>b.y;
            }
            return x>b.x;
        }
        return height>b.height;
    }
    bool operator > (node b) const
    {
        if(height==b.height)
        {
            if(x==b.x)
            {
                return y<b.y;
            }
            return x<b.x;
        }
        return height<b.height;
    }
};
set<node>mark;
priority_queue<node>prique;
int BFS(pair<int,int>st)
{
    int minborder=0x3f3f3f3f;
    int area=0;
    memset(vis,false,sizeof(vis));
    vector<pair<int,int> >neigh;
    neigh.clear();
    queue<pair<int,int> >que;
    while(!que.empty()) que.pop();
    que.push(st);
    while(!que.empty())
    {
        pair<int,int>now=que.front();
        neigh.push_back(now);
        que.pop();
        vis[now.first][now.second]=true;
        if(now.first==1||now.first==R||now.second==1||now.second==C)//at the border
        {
            return 0;
        }
        area++;
        for(int i=0;i<4;i++)
        {
            int nextx=now.first+dx[i];
            int nexty=now.second+dy[i];
            if(nextx<1||nextx>R||nexty<1||nexty>C) continue;
            if(vis[nextx][nexty]==true) continue;
            if(mp[nextx][nexty]>mp[st.first][st.second])
            {
//                cout<<mp[nextx][nexty]<<endl;
                minborder=min(minborder,mp[nextx][nexty]);
                continue;
            }
            else if(mp[nextx][nexty]<mp[now.first][now.second])
            {
                return 0;
            }
            else if(mp[nextx][nexty]==mp[now.first][now.second])
            {
                que.push(make_pair(nextx,nexty));
                vis[nextx][nexty]=true;
            }
            //if smaller?
            //calc sum(heigh gap) instead of using product once
        }
    }
//   cout<<"here "<<st.first<<" "<<st.second<<" "<<area<<" "<<minborder<<" "<<mp[st.first][st.second]<<endl;
    if(minborder==0x3f3f3f3f) return 0;
    int ret=0;
    for(int i=0;i<neigh.size();i++)
    {
//        cout<<neigh[i].first<<" "<<neigh[i].second<<" "<<mp[neigh[i].first][neigh[i].second]<<" "<<st.first<<" "<<st.second<<" "<<mp[st.first][st.second]<<endl;
        mark.insert(node(neigh[i].first,neigh[i].second,mp[neigh[i].first][neigh[i].second]));
        ret+=minborder-mp[neigh[i].first][neigh[i].second];
        mp[neigh[i].first][neigh[i].second]=minborder;
        prique.push(node(neigh[i].first,neigh[i].second,mp[neigh[i].first][neigh[i].second]));//neigh's height must < minborder
    }
//    cout<<"ret: "<<ret<<endl;
    return ret;//update value of mp?
}
int tmpmp[maxn][maxn];
int main()
{
    freopen("B-small-practice.in","r",stdin);
    freopen("B-small-practice.out","w",stdout);
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        scanf("%d %d",&R,&C);
        memset(mp,0,sizeof(mp));
        memset(tmpmp,0,sizeof(tmpmp));
        while(!prique.empty()) prique.pop();
        mark.clear();
        ans=0;
        for(int i=1;i<=R;i++)
        {
            for(int j=1;j<=C;j++)
            {
                scanf("%d",&mp[i][j]);
                tmpmp[i][j]=mp[i][j];
                if(i==1||j==1||i==R||j==C) continue;
                prique.push(node(i,j,mp[i][j]));
            }
        }
        while(!prique.empty())
        {
            node tmp=prique.top();
            prique.pop();
//            cout<<tmp.x<<" "<<tmp.y<<" "<<tmp.height<<" "<<mark.count(tmp)<<endl;
//            continue;
            if(mark.count(tmp)==0)
            {
                
                ans+=BFS(make_pair(tmp.x,tmp.y));
            }
        }
        printf("Case #%d: %d\n",ca,ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值