NOIp提高組 2005 過河————dp+路徑壓縮

題解:本題主要考查dp+路徑壓縮。
簡要題意:有一條n(n<=109)n(n<=10^9)米長的橋,橋上有mm個石頭。小青蛙從橋頭開始,向終點跳。跳躍距離爲SSTT,求青蛙最少需要踩到的石子數。
1.dp:本題的難點不在dp的轉移方程上,易得出:設f[i]f[i]爲在ii上經過的石頭數
位置上有石頭:f[i]=min(f[i],f[ij]+1);f[i]=min(f[i],f[i-j]+1);
位置上無石頭:f[i]=min(f[i],f[ij]);f[i]=min(f[i],f[i-j]);
2.路徑壓縮:本題nn的規模極大,但mm很小,所以就需要巧妙的路徑壓縮。我們發現sts*t以後的每個點都可以到達, 所以我們只需將每兩個石頭超過sts*t的距離縮成sts*t就可以了
代碼如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int stone[233333],v[999999],f[233333],a[233333];
int n,s,t,m,ans=0x3f3f3f,d;
int main()
{
	cin>>n>>s>>t>>m;
	for(int i=1;i<=m;i++)cin>>stone[i];
	sort(stone+1,stone+m+1);
	if(s==t)
	{
		int sum=0;
		for(int i=1;i<=m;i++)
		if(stone[i]%s==0)sum++;
		cout<<sum<<endl;cin>>n;
		return 0;
	}
	for(int i=1;i<=m;i++)
	{
		d=stone[i]-stone[i-1];
		if(d>s*t)d=s*t;
		a[i]=a[i-1]+d;
		v[a[i]]=1;
	}
    if(a[m]+s*t<n)
	n=a[m]+s*t;
	memset(f,0x3f3f3f,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++)
	for(int j=s;j<=t;j++)
	if(i>=j)
	{
		if(v[i]==1)f[i]=min(f[i],f[i-j]+1);
		else f[i]=min(f[i],f[i-j]);
	}
	for(int i=1;i<=n;i++)
	ans=min(ans,f[n]);
	cout<<ans<<endl;
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章