zoukankan      html  css  js  c++  java
  • 开车旅行

    题目链接

    真真一道倍增好题。

    先说70分思路

    我的:
    从后边的城市往前跑,这样就能(n^2)时间内得到从城市(i)到城市(j)的路程了。........反正超级麻烦,最后也没写出来。后来想想最直接的暴力好像是(n*m),70分也能过。

    代码估计以后也看不懂了。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int N = 1005;
    const int inf = 2147483647;
    map<int,map<int,int> >mp;
    int n,h[N],m,s[N],x[N],x0,dis[1005][1005],dist[N],dis1[N][2];
    int head[N],tot,maxx[N][21],min1,min2,id1[N],id2[N];
    int head1[N],tot1,disa[1005][1005][2],disb[1005][1005][2],ansxo;
    struct edge{
    	int node,next,data;
    }e[N<<1],e1[N<<1];
    struct node{
    	int tmp[N];
    }a[N];
    void add(int x,int y)
    {
    	e[++tot].node=y; e[tot].next=head[x];
    	head[x]=tot; 
    }
    void add1(int x,int y)
    {
    	e1[++tot1].node=y; e1[tot1].next=head1[x];
    	head1[x]=tot1; 
    }
    inline int read()
    {
    	char c=getchar();
    	int ans=0,w=1;
    	while((c<'0'||c>'9')&&c!='-') c=getchar();
    	if(c=='-') { w=-1;c=getchar(); }
    	while(c>='0'&&c<='9')
    	{ ans=ans*10+c-'0'; c=getchar(); }
    	return ans*w; 
    }
    void dfs(int t,int u,int ft,int flag,int lena,int lenb)
    {
    //	if(u==1) return ;
    	if(flag) 
    	{
    		for(int i=head[u];i;i=e[i].next)
    		{
    			int v=e[i].node;
    			disa[v][t][ft]=lena+e[i].data;
    			disb[v][t][ft]=lenb;
    			a[v].tmp[t]=disa[v][t][ft]+disb[v][t][ft];
    			mp[v][a[v].tmp[t]]=t;
    			dfs(t,v,ft,0,lena+e[i].data,lenb);
    		}
    	}
    	else 
    	{
    		for(int i=head1[u];i;i=e1[i].next)
    		{
    			int v=e1[i].node;
    			dfs(t,v,ft,1,lena,lenb+e1[i].data);
    		}
    	}
    } 
    double chu(int a,int b)
    {
    	if(b==0) return 2e9;
    	return a/b;
    }
    int main()
    {
    //	memset(min1,0x3f,sizeof(min1));
    //	memset(min2,0x3f,sizeof(min2));
    	n=read();
    	for(int i=1;i<=n;i++) h[i]=read();
    	x0=read(); m=read();
    	for(int i=1;i<=m;i++)
    	 s[i]=read(),x[i]=read();
    	for(int i=1;i<=n;i++)
    	{
    		min1=min2=inf;
    //		id1=n+1,id2=n+1;
    	 for(int j=i+1;j<=n;j++)
    	 {
    	 	dis[i][j]=abs(h[i]-h[j]);
    	 	if(dis[i][j]==min1&&)
    	 	{
    	 		if(h[j]<h[id1[i]])
    	 		{
    	 			min2=min1; id2[i]=id1[i];
    	 		    min1=dis[i][j]; id1[i]=j;
    	 		}
    	 		else min2=dis[i][j],id2[i]=j;
    	 		continue;
    	 	}
    	 	if(dis[i][j]==min2&&h[j]<h[id2[i]])
    	 	{
    	 		min2=dis[i][j]; id2[i]=j;
    	 		continue;
    	 	}
    	 	if(dis[i][j]<min1)
    	 	 min2=min1,min1=dis[i][j],id2[i]=id1[i],id1[i]=j;
    		else if(dis[i][j]<min2)
    		 min2=dis[i][j],id2[i]=j;
    	 }
        }
    	for(int i=1;i<=n;i++)
    	add1(id1[i],i),add(id2[i],i);
    	for(int i=1;i<=n;i++)
    	{
    		dfs(i,i,0,0,0,0); dfs(i,i,1,1,0,0);
    	}
    	double ansx=2e9;
    	for(int i=1;i<=n;i++)
    	{
    		sort(a[i].tmp+1,a[i].tmp+n+1);
    		int l=1,r=n,ansp;
    		while(l<=r)
    		{
    			int mid=(l+r)>>1;
    			if(a[i].tmp[mid]<=x0) l=mid+1,ansp=mid;
    			else r=mid-1;
    		}
    		int tt=mp[i][a[i].tmp[ansp]];
    		if(chu(disa[i][tt],disb[i][tt])<ansx) ansx=(disa[i][tt]/disb[i][tt]),ansxo=i;
    		if(chu(disa[i][n],disb[i][n])<ansx) ansx=(disa[i][n]/disb[i][n]),ansxo=i;
    	}
    } 
    

    (llfz)的:
    最最暴力的解法。以每个点为起点,进行(dfs)。但是这么简单的思路在调试时还是出现了很多错误。导致第一次提交只有15分。
    错点:
    初始化漏掉情况((min1)表示最近(min2)表示次近,(id1)(id2)分别记录最近和次近的编号,(dis[i][j])暂且表示城市(i)到城市(j)的距离)

    1.有相等的情况

    (min1)相等
    分海拔与(id1)比较的两种情况
    如果海拔比(id1)高,还要与(id2)比较海拔,不能直接赋值。万一(min1==min2)(id2)的海拔更低呢。

    2.没有相等的情况

    这个比较简单,先比较(min1)再比较(min2)就行了。

    更新答案时漏掉情况。
    如果小B走的距离是0,也有可能更新答案。注意,这次是选海拔高的城市。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    using namespace std;
    const int N = 1005;
    const int inf = 2e9;
    int n,h[N],x0,m,s[10*N],x[10*N],st;
    int min1=inf,min2=inf,id1[N],id2[N];
    double ans=2e9;
    bool book;
    void dfs1(int u,int flag,int s1,int s2,int xp)
    {
    	if(book) return ;
    	if(u==n)
    	{
    		book=1;
    		printf("%d %d
    ",s1,s2);
    		return ;
    	}
    	if(u==n-1&&flag)
    	{
    		book=1;
    		printf("%d %d
    ",s1,s2);
    		return ;
    	}
    	if(flag)
    	{
    		if(abs(h[u]-h[id2[u]])+s1+s2>xp)
    		{
    		    book=1;
    		    printf("%d %d
    ",s1,s2);
    		    return ;
    	    }
    	    dfs1(id2[u],0,s1+abs(h[u]-h[id2[u]]),s2,xp);
    	}
    	else
    	{
    		if(abs(h[u]-h[id1[u]])+s1+s2>xp)
    		{
    		    book=1;
    		    printf("%d %d
    ",s1,s2);
    		    return ;
    	    }
    	    dfs1(id1[u],1,s1,s2+abs(h[u]-h[id1[u]]),xp);
    	}
    }
    double dfs(int begin,int u,int flag,int s1,int s2,int xp)
    {
    	if(u==n)
    	{
    		if(s2==0) return 2e9;
    		else return (double)s1/s2;
    /*		if(s2==0) return ;
    //		if(s2==0&&h[begin]>h[st]&&ans==(double)2e9) { st=begin; return ;}
    		if((double)(s1/s2)==ans&&h[begin]>h[st])
    		  st=begin;
    		if((double)(s1/s2)<ans)
    		 ans=(double)(s1/s2),st=begin;
    		return ;*/
    	}
    	if(u==n-1&&flag)
    	{
    		if(s2==0) return 2e9;
    		else return (double)s1/s2;
    /*		if(s2==0) return ;
    //		if(s2==0&&h[begin]>h[st]&&ans==(double)2e9) { st=begin; return ;}
    		if((double)(s1/s2)==ans&&h[begin]>h[st])
    		  st=begin;
    		if((double)(s1/s2)<ans)
    		 ans=(double)(s1/s2),st=begin;
    		return ;*/
    	}
    	if(flag)
    	{
    		if(abs(h[u]-h[id2[u]])+s1+s2>xp)
    		{
    		if(s2==0) return 2e9;
    		else return (double)s1/s2;
    /*		    if(s2==0) return ;
    //		    if(s2==0&&h[begin]>h[st]&&ans==(double)2e9) { st=begin; return ;}
    		    if((double)(s1/s2)==ans&&h[begin]>h[st])
    		     st=begin;
    		    if((double)(s1/s2)<ans)
    		     ans=(double)(s1/s2),st=begin;
    		    return ;*/
    	    }
    	    dfs(begin,id2[u],0,s1+abs(h[u]-h[id2[u]]),s2,xp);
    	}
    	else
    	{
    		if(abs(h[u]-h[id1[u]])+s1+s2>xp)
    		{
    		    if(s2==0) return 2e9;
    		    else return (double)s1/s2;
    /*		    if(s2==0) return ;
    //		    if(s2==0&&h[begin]>h[st]&&ans==(double)2e9) { st=begin; return ;}
    		    if((double)(s1/s2)==ans&&h[begin]>h[st])
    		     st=begin;
    		    if((double)(s1/s2)<ans)
    		     ans=(double)(s1/s2),st=begin;
    		    return ;*/
    	    }
    	    dfs(begin,id1[u],1,s1,s2+abs(h[u]-h[id1[u]]),xp);
    	}
    }
    int main()
    {
    //	freopen("a.in","r",stdin);
    //	freopen("a.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	 scanf("%d",&h[i]);
    	h[0]=2e9;
    	scanf("%d%d",&x0,&m);
    	for(int i=1;i<=m;i++)
    	 scanf("%d%d",&s[i],&x[i]);
    	for(int i=1;i<=n;i++)
    	{ min1=min2=inf;
    	 for(int j=i+1;j<=n;j++)
    	 {
    	 	if(min1==abs(h[i]-h[j]))
    	 	{
    	 		if(h[j]<h[id1[i]])
    	 		{
    	 			min2=min1; id2[i]=id1[i];
    	 			min1=abs(h[i]-h[j]); id1[i]=j;
    	 		} 
    	 		else 
    	 		{
    	 			if(min2==abs(h[i]-h[j])&&h[j]<h[id2[i]])
    	 			 min2=abs(h[i]-h[j]),id2[i]=j;
    	 			if(min2>abs(h[i]-h[j]))
    	 			 min2=abs(h[i]-h[j]),id2[i]=j;
    	 		}
    	 		continue;
    	 	} 
    	 	if(min2==abs(h[i]-h[j]))
    	 	{
    	 		if(h[j]<h[id2[i]])
    	 		 min2=abs(h[i]-h[j]),id2[i]=j;
    	 		continue;
    	 	}
    	 	if(min1>abs(h[i]-h[j])) 
    	 	{
    	 		min2=min1; id2[i]=id1[i];
    	 		min1=abs(h[i]-h[j]); id1[i]=j;
    	 	}
    	 	else if(min2>abs(h[i]-h[j]))
    	 	 min2=abs(h[i]-h[j]),id2[i]=j;
    	 }
        }
        for(int i=1;i<=n;i++)
        {
        	double t=dfs(i,i,1,0,0,x0);
        	if(t<ans) { ans=t; st=i;}
        	if(t==ans&&h[i]>h[st]) { ans=t,st=i;}
        }
        printf("%d
    ",st);
        for(int i=1;i<=m;i++)
        {
        	book=0;
        	dfs1(s[i],1,0,0,x[i]);
        }
        return 0;
    }
    

    果然还是(llfz)强。

    正解

    对于每个点来说,以它为起点的路径是唯一的。用(f[i][j])表示从第(i)点开始向后(2*2^j)步到达的点,同样(sta[i][j])(stb[i][j])记录小A和小B走的路径长度。

    看的大佬的这篇博客

    以后好好复习代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define LL long long
    using namespace std;
    const int N = 100005;
    int n,m,l,r,j;
    struct node{
    	int i,v,l,r;
    	bool friend operator < (const node& a,const node& b){
    		return a.v<b.v;
    	}
    }d[N];
    int h[N],p[N],sta[N][21],stb[N][21],f[N][21];
    int na[N],nb[N],a,b,ans=n;
    double minn = 2e9;
    bool zuo()
    {
    	if(!l) return 0;
    	if(!r) return 1;
    	return d[j].v-d[l].v<=d[r].v-d[j].v;
    }
    int pd(int a,int b)
    {
    	if(!a) return d[b].i;
    	if(!b) return d[a].i;
    	if(d[j].v-d[a].v<=d[b].v-d[j].v) return d[a].i;
    	return d[b].i;
    }
    void make_st()
    {
    //	int i,j;
    	for(int j=1;j<=19;j++)
    	 for(int i=1;i<=n;i++)
    	 {
    	 	f[i][j]=f[f[i][j-1]][j-1];
    	 	sta[i][j]=sta[i][j-1]+sta[f[i][j-1]][j-1];
    	 	stb[i][j]=stb[i][j-1]+stb[f[i][j-1]][j-1];
    	 }
    }
    void getab(LL x,int p)
    {
    	a=b=0;
    	for(int i=19;i>=0;i--)
    	{
    		if(f[p][i]&&(LL)(a+b+sta[p][i]+stb[p][i])<=x)
    		{
    			a+=sta[p][i]; b+=stb[p][i];
    			p=f[p][i];
    		}
    	}
    	if(na[p]&&a+b+sta[p][0]<=x) a+=sta[p][0];
    } 
    int main()
    {
    	LL x;
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",&d[i].v);
    	for(int i=1;i<=n;i++) d[i].i=i;
    	sort(d+1,d+n+1);
    	for(int i=1;i<=n;i++) p[d[i].i]=i;//p[i]表示编号为i的城市当前在的位置  
    	for(int i=1;i<=n;i++) d[i].l=i-1,d[i].r=i+1;
    	d[1].l=d[n].r=0;
    	for(int i=1;i<=n;i++)
    	{
    		j=p[i]; l=d[j].l; r=d[j].r;
    		if(zuo()) nb[i]=d[l].i,na[i]=pd(d[l].l,r);
    		else nb[i]=d[r].i,na[i]=pd(l,d[r].r);
    		if(l) d[l].r=r; if(r) d[r].l=l;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		f[i][0]=nb[na[i]];//小A先走,走到na[i],然后小B再走,走到nb[na[i]]  
    		sta[i][0]=abs(d[p[i]].v-d[p[na[i]]].v);
    		stb[i][0]=abs(d[p[f[i][0]]].v-d[p[na[i]]].v);
    	}
    	make_st();
    	scanf("%lld%d",&x,&m);
    	for(int i=1;i<=n;i++)
    	{
    		getab(x,i);
    		if(b&&1.0*a/b<minn)
    		{
    			minn=1.0*a/b;
    			ans=i;
    		}
    	}
    	printf("%d
    ",ans);
    	for(int i=1;i<=m;i++)
    	{
    		scanf("%d%lld",&j,&x);
    		getab(x,j);
    		printf("%d %d
    ",a,b);
    	}
    	return 0;
    }
    

    全靠代码占长度。。。

  • 相关阅读:
    信息安全[0836]
    05 二极管的微变等效和稳压二极管
    04 二极管的直流等效通路
    STM32 ADS112C04
    03 PN与二极管的特性
    STM32中的程序在RAM还是FLASH里运行?
    基于STM32的MLX90614人体红外测温枪
    KEIL5如何打开KEIL4工程 [复制链接]
    02 PN结的形成
    PreparedStatement和Statament的性能
  • 原文地址:https://www.cnblogs.com/karryW/p/11405774.html
Copyright © 2011-2022 走看看