【图论·习题】同余最短路:跳楼机

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Ronaldo7_ZYB/article/details/87680707

题目描述

Srwudi的家是一幢h层的摩天大楼。由于前来学习的蒟蒻越来越多,srwudi改造了一个跳楼机,使得访客可以更方便的上楼。
经过改造,srwudi的跳楼机可以采用以下四种方式移动:

  • 向上移动x层;
  • 向上移动y层;
  • 向上移动z层;
  • 回到第一层。
    一个月黑风高的大中午,DJL来到了srwudi的家,现在他在srwudi家的第一层,碰巧跳楼机也在第一层。
    DJL想知道,他可以乘坐跳楼机前往的楼层数。

题解

首先,我们需要思考一下两个数应该怎么解决:若数为x和y。

  • x x + y , x + 2 y , x + 3 y . . . x:x+y,x+2y,x+3y...
  • 2 x 2 x + y , 2 x + 2 y , 2 x + 3 y . . . 2x:2x+y,2x+2y,2x+3y...
  • 3 x 3 x + y , 3 x + 2 y , 3 x + 3 y . . . 3x:3x+y,3x+2y,3x+3y...

大体的枚举方式就是这样的。但是我们会发现,这样的枚举效率不是很高。

例如,当 3 x x   %   y   =   0 3x-x\ \%\ y\ =\ 0 时, 3 x 3x 后的枚举就是无效的,因为会被若干个y填充。

所以最后的结果就是,求得若干个 k x   %   y kx\ \%\ y 不同的 k k a n s =   h k x y ans=\sum \ \frac{h-k*x}{y}

对于三个数,思路也是一样的。求解的是 a x + b y + c z + 1 h ax+by+cz+1≤h 的情况。

f ( i ) f(i) 表示 ( b y + c z )   %   z   =   i (by+cz)\ \%\ z\ =\ i 时, b x + c z bx+cz 的最小值。

  • f ( i ) + y = f ( ( i + y )   %   z ) f(i)+y=f((i+y)\ \%\ z)
  • f ( i ) + z = f ( ( i + z )   %   z ) f(i)+z=f((i+z)\ \%\ z)

这样一个式子,正好对应了一个最短路的模型。以1为起点跑最短路就能够得到相应的 f f 值。

同理, a n s =   h f i y ans=\sum \ \frac{h-f_{i}}{y}

这道题其实我们,对于同余的题,从其重复性中找到一些优化求解的方法;若能够列出图论迭代式的形式,则可以用图论来求出相应的模型值。而这道题的主要难点就是根据数学模型建模,以最短路的形式辅助求解。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
#include<limits.h>
#include<algorithm>
#define LL long long
#define Mp make_pair

using namespace std;

LL h,x,y,z,ans=0;
LL v[200000];
LL dis[200000];
priority_queue< pair<LL,LL> >q;  
vector< pair<LL,LL> >a[200000];

int main(void)
{
	freopen("srwudi.in","r",stdin);
	freopen("srwudi.out","w",stdout);
	cin>>h>>x>>y>>z;
	if (x == 1 || y == 1 || z == 1)
	{
		cout<<h<<endl;
		return 0;
	}
	for (LL i=0;i<x;++i)
	{
		a[i].push_back(Mp((i+y)%x,y));			
		a[i].push_back(Mp((i+z)%x,z));
	}
	memset(dis,30,sizeof(dis));
	dis[1]=1;
	q.push(Mp(1,1));
	while (q.size())
	{
		LL now=q.top().second;
		q.pop();
		if (v[now] == 1) continue;
		v[now]=1;
		for (LL i=0;i<a[now].size();++i)
		{
			LL next=a[now][i].first,val=a[now][i].second;
			if (dis[now]+val < dis[next])
			{
				dis[next]=dis[now]+val;
				q.push( Mp(-dis[next] , next) );
			}
		}
	}
	for (LL i=0;i<x;++i)
	    if (h-dis[i] >= 0) 
		    ans+=(h-dis[i])/x+1;
	cout<<ans<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Ronaldo7_ZYB/article/details/87680707
今日推荐