邻接表与链式前向星

ZOJ 3877 Earthstone Keeper

又遇到了一道卡空间常数的题目。

如果用链式前向星就刚好卡过,如果用邻接表就超空间。

原因是本题点巨多(1e5),但边相对来讲巨少(每个点最多8条边)。

如果用邻接表来实现的话,一般就用vector嘛,我们都知道vector都是自动扩容的,在空间满了以后,就自动申请多一倍空间。

如下代码所示。

#include
#define f(i) for(int i=1;i<=N;i++)
using namespace std;
const int N = 100;

int main()
{
    vectorvec;
    f(i)
    {
        vec.push_back(i);
        printf("%d: %d\n",i,vec.capacity());
    }
    return 0;
}
所以在本题中,如果用vector的话,就会莫名其妙地多申请[0,1]倍的空间,本来就卡得很紧,一多申请空间,就爆了。

而链式前向星是一开始申请好空间后,就不变了,如果按照最坏情况所需的空间申请的话,就刚刚好卡过空间限制。

所以。。以后注意吧。。


然后是关于本题的一些解题思路。主要就是觉得怪物难处理嘛,其他都很正常。显然我们肯定不会回到以前来到过的格子,因为如果我现在回来再走,不如当时就这样走。但是怪物不止控制一个格子,而是5个格子,还是十字架形状的。经过思考后我们就会发现,我们也不会回到曾经到过的十字架区域。原因很简单,因为十字架的中心是怪物,怪物死后,中心就变成普通的土地了(既不是障碍物,也没有陷阱,更没有第二只怪物控制这个格子)。如果我们已经进入了十字架区域且以后还想再来到这个十字架区域,不如直接走到中心,然后再往其他三个方向走,因为这一定是最优的。所以一旦离开就没必要再回来了。


但是我考虑漏了一点。。。

就是如果我同时在两个十字架控制的格子上,又想去这两个十字架共同控制的另一个格子,那么我必然会离开其中某一个十字架,再回来的。所以炸了一个小时的WA。。。然后又炸了两个小时的MLE。。。

抖机灵的想法最容易出错了,以后要注意吧。。。


代码

#include
using namespace std;
typedef long long ll;
typedef pair pll;
const ll maxn = 510;
const ll MAIN = 300000;
const ll inf = LONG_LONG_MAX>>2;

struct Node
{
    ll to,dist,next;
}edges[(maxn*maxn)<<3];
ll head[maxn*maxn],cnt;
void Init(ll n)
{
    for(ll i=1;i<=n;i++) head[i]=-1;
    cnt=0;
}
void add(ll from,ll to,ll dist)
{
    edges[cnt].to=to;
    edges[cnt].dist=dist;
    edges[cnt].next=head[from];
    head[from]=cnt++;
}

struct HeapNode
{
    ll d,u;
    bool operator < (const HeapNode& rhs) const
    {
        return d>rhs.d;
    }
};

struct Dijkstra
{
    ll n,m;
    ll d[maxn*maxn];
    ll p[maxn*maxn];
    ll done[maxn*maxn];

    void init(ll n)
    {
        this->n=n;
        Init(n<<3);
    }
    void AddEdge(ll from,ll to,ll dist)
    {
        add(from,to,dist);
    }
    void dijkstra(ll s)
    {
        for(ll i=1;i<=n;i++)
        {
            done[i]=0;
            d[i]=inf;
        }
        d[s]=0;
        priority_queueQ;
        Q.push((HeapNode){0,s});
        while(!Q.empty())
        {
            HeapNode x=Q.top();
            Q.pop();
            ll u=x.u;
            if(done[u]) continue;
            done[u]=1;
            for(ll i=head[u];~i;i=edges[i].next)
            {
                Node& e=edges[i];
                if(d[e.to]>d[u]+e.dist)
                {
                    d[e.to]=d[u]+e.dist;
                    p[e.to]=i;
                    Q.push((HeapNode){d[e.to],e.to});
                }
            }
        }
    }
}DIJ;

ll dr[4]={-1, 0, 1, 0};
ll dc[4]={ 0, 1, 0,-1};

ll N,M,SR,SC,TR,TC;
char MAP[maxn][maxn];

inline ll id(ll r,ll c)
{
    return (r-1)*M+c;
}

bool ok(ll i,ll j)
{
    return 1<=i&&i<=N&&1<=j&&j<=M;
}

void solve()
{
    scanf("%lld %lld %lld %lld %lld %lld",&N,&M,&SR,&SC,&TR,&TC);
    DIJ.init(N*M);
    for(ll i=1;i<=N;i++) scanf("%s",MAP[i]+1);
    for(ll i=1;i<=N;i++) for(ll j=1;j<=M;j++) if(MAP[i][j]!='#')
    {
        if(isupper(MAP[i][j]))
        {
            for(ll u=0;u<4;u++) for(ll v=0;v<4;v++) if(u!=v)
            {
                pll sb=make_pair(i+dr[u],j+dc[u]);
                if(!ok(sb.first,sb.second)) continue;
                if(MAP[sb.first][sb.second]=='#') continue;
                sb=make_pair(i+dr[v],j+dc[v]);
                if(!ok(sb.first,sb.second)) continue;
                if(MAP[sb.first][sb.second]=='#') continue;
                sets;
                for(ll k=0;k<4;k++)
                {
                    pll p=make_pair(i+dr[u]+dr[k],j+dc[u]+dc[k]);
                    if(!ok(p.first,p.second)) continue;
                    if(isupper(MAP[p.first][p.second])) s.insert(p);
                }
                s.erase(make_pair(i,j));
                ll D=2;
                for(ll k=0;k<4;k++)
                {
                    pll p=make_pair(i+dr[v]+dr[k],j+dc[v]+dc[k]);
                    if(!ok(p.first,p.second)) continue;
                    if(isupper(MAP[p.first][p.second])&&s.count(p)) s.erase(p);
                }
                for(set::iterator it=s.begin();it!=s.end();++it) D+=(MAP[it->first][it->second]-'A'+1)*MAIN;
                DIJ.AddEdge(id(i+dr[v],j+dc[v]),id(i+dr[u],j+dc[u]),D+(MAP[i+dr[u]][j+dc[u]]=='.'?0:(MAP[i+dr[u]][j+dc[u]]-'a'+1)*MAIN));
            }
        }
        else
        {
            for(ll k=0;k<4;k++)
            {
                pll p=make_pair(i+dr[k],j+dc[k]);
                if(ok(p.first,p.second)&&MAP[p.first][p.second]!='#'&&!isupper(MAP[p.first][p.second]))
                {
                    ll D=0;
                    for(ll l=0;l<4;l++)
                    {
                        pll sb=make_pair(p.first+dr[l],p.second+dc[l]);
                        if(!ok(sb.first,sb.second)) continue;
                        if(isupper(MAP[sb.first][sb.second])) D+=(MAP[sb.first][sb.second]-'A'+1)*MAIN;
                    }
                    DIJ.AddEdge(id(i,j),id(p.first,p.second),D+(MAP[p.first][p.second]=='.'?1:(MAP[p.first][p.second]-'a'+1)*MAIN+1));
                }
            }
        }
    }
    DIJ.dijkstra(id(SR,SC));
    ll ID=id(TR,TC);
    printf("%lld %lld\n",DIJ.d[ID]/MAIN,DIJ.d[ID]%MAIN);
}

int main()
{
    ll T;
    scanf("%lld",&T);
    while(T--) solve();
    return 0;
}


你可能感兴趣的:(经验,最短路,Dijkstra,链式前向星,图论)