您的位置:首页 > 其它

[SPFA 分块建图] BZOJ 4070 [Apio2015]雅加达的摩天楼

2016-05-04 13:40 357 查看
最坏情况有n^2条边,一般最短路算法都不能过。
考虑用分块的思想来优化建图。
Pi>sqrt(n),暴力加入每一条边,每次最多sqrt(n)条边。
Pi≤sqrt(n),对于每个点添加sqrt(n)个辅助点,一层一层走,边数是O(n*sqrt(n))的。
总边数和总点数都是O(n*sqrt(n))。
块不能太大 不然爆内存 块最大100

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define V G[p].v
#define P(x,y) ((x)*n+(y))
using namespace std;

inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}

inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=4000005;
const int M=15000005;

struct edge{
int v,w;
int next;
};

edge G[M];
int head
,inum;

inline void add(int u,int v,int w,int p){
G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;
}

const int ND=N;
int Q[ND],l,r;
int ins
,dis
;

int n,m,S,T,B;
int b[30005],p[30005];

inline void SPFA(int S){
int u;
for (int i=1;i<=P(B,n);i++)
dis[i]=1<<30,ins[i]=0;
l=r=-1;
dis[S]=0; Q[(++r)%ND]=S; ins[S]=1;
while (l!=r){
u=Q[(++l)%ND]; ins[u]=0;
for (int p=head[u];p;p=G[p].next)
if (dis[V]>dis[u]+G[p].w)
{
dis[V]=dis[u]+G[p].w;
if (!ins[V])
Q[(++r)%ND]=V,ins[V]=1;
}
}
}

int main()
{
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++) read(b[i]),b[i]++,read(p[i]);
S=b[1]; T=b[2];
B=min((int)sqrt(n),100);
for (int i=1;i<=B;i++)
for (int j=1;j<=n;j++)
add(P(i,j),j,0,++inum);
for (int i=1;i<=B;i++)
for (int j=1;j<=n-i;j++)
add(P(i,j),P(i,j+i),1,++inum),add(P(i,j+i),P(i,j),1,++inum);
for (int i=1;i<=m;i++)
if (p[i]<=B)
add(b[i],P(p[i],b[i]),0,++inum);
else
{
for(int j=1;b[i]+j*p[i]<=n;j++) add(b[i],b[i]+j*p[i],j,++inum);
for(int j=1;b[i]-j*p[i]>=1;j++) add(b[i],b[i]-j*p[i],j,++inum);
}
SPFA(S);
if (dis[T]==1<<30)
printf("-1\n");
else
printf("%d\n",dis[T]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: