zoukankan      html  css  js  c++  java
  • bzoj 4070: [Apio2015]雅加达的摩天楼【spfa】

    明明是个最短路却有网络流一样的神建图= A =
    首先要是暴力建图的话最坏有O(nm)条边。所以优化建图。
    考虑分块思想,设bs=sqrt(n),对于p大于bs的,直接连边即可,最多有sqrt(n)条,注意边权不全是1了,因为要从b走过去;对于p小于等于bs,先把每栋楼建sqrt个辅助点,然后这些辅助点向原点连边,其中i点的辅助点j表示i栋楼可以跳p步。这些辅助点同层之间连双向边。然后对于一只狗,直接连接b点与b点的第p辅助点即可。
    spfa即可
    然而事实证明bs取sqrt甚至会re,直接取100会好一些

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    using namespace std;
    const int N=30005,inf=1e9;
    int n,m,b[N],p[N],h[N*200],cnt,bs,dis[N*200];
    bool v[N*200];
    queue<int>q;
    struct qwe
    {
    	int ne,to,va;
    }e[N*500];
    int read()
    {
    	int r=0,f=1;
    	char p=getchar();
    	while(p>'9'||p<'0')
    	{
    		if(p=='-')
    			f=-1;
    		p=getchar();
    	}
    	while(p>='0'&&p<='9')
    	{
    		r=r*10+p-48;
    		p=getchar();
    	}
    	return r*f;
    }
    void add(int u,int v,int w)
    {
    	cnt++;
    	e[cnt].ne=h[u];
    	e[cnt].to=v;
    	e[cnt].va=w;
    	h[u]=cnt;
    }
    int main()
    {
    	n=read(),m=read();
    	bs=min((int)sqrt(n),100);
    	for(int i=1;i<=m;i++)
    		b[i]=read()+1,p[i]=read();
    	for(int i=1;i<=bs;i++)
    		for(int j=1;j<=n;j++)
    			add(i*n+j,j,0);
    	for(int i=1;i<=bs;i++)
    		for(int j=1;j<=n-i;j++)
    			add(i*n+j,i*n+j+i,1),add(i*n+j+i,i*n+j,1);
    	for(int i=1;i<=m;i++)
    	{
    		if(p[i]<=bs)
    			add(b[i],p[i]*n+b[i],0);
    		else
    		{
    			// for(int j=b[i]-b[i]/p[i]*p[i];j<=n;j+=p[i])
    				// add(b[i],j,abs(b[i]-j)/p[i]);
    			for(int j=1;b[i]+j*p[i]<=n;j++) 
    				add(b[i],b[i]+j*p[i],j);  
                for(int j=1;b[i]-j*p[i]>=1;j++) 
    				add(b[i],b[i]-j*p[i],j);  
    		}
    	}
    	for(int i=1;i<=n*200;i++)
    		dis[i]=inf;
    	int s=b[1],t=b[2];
    	dis[s]=0,v[s]=1,q.push(s);
    	while(!q.empty())
    	{
    		int u=q.front();//cerr<<u<<endl;
    		q.pop();
    		v[u]=0;
    		for(int i=h[u];i;i=e[i].ne)
    			if(dis[e[i].to]>dis[u]+e[i].va)
    			{
    				dis[e[i].to]=dis[u]+e[i].va;
    				if(!v[e[i].to])
    				{
    					v[e[i].to]=1;
    					q.push(e[i].to);
    				}
    			}
    	}
    	printf("%d
    ",dis[t]==inf?-1:dis[t]);
    	return 0;
    }
    
  • 相关阅读:
    53. Maximum Subarray
    64. Minimum Path Sum
    28. Implement strStr()
    26. Remove Duplicates from Sorted Array
    21. Merge Two Sorted Lists
    14. Longest Common Prefix
    7. Reverse Integer
    412. Fizz Buzz
    linux_修改域名(centos)
    linux_redis常用数据类型操作
  • 原文地址:https://www.cnblogs.com/lokiii/p/8805914.html
Copyright © 2011-2022 走看看