开车旅行

题目链接

真真一道倍增好题。

先说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\n",s1,s2);
		return ;
	}
	if(u==n-1&&flag)
	{
		book=1;
		printf("%d %d\n",s1,s2);
		return ;
	}
	if(flag)
	{
		if(abs(h[u]-h[id2[u]])+s1+s2>xp)
		{
		    book=1;
		    printf("%d %d\n",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\n",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\n",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\n",ans);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%lld",&j,&x);
		getab(x,j);
		printf("%d %d\n",a,b);
	}
	return 0;
}

全靠代码占长度。。。

posted @ 2019-08-24 19:33  蟹蟹王  阅读(171)  评论(0编辑  收藏  举报