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;
}