HDU 6071 Lazy Running(同余最短路)

简述题意:给你一个由四个节点组成的环,相邻两点间可达,求从节点2出发,回到节点2的不小于k的最短路径的长度。

算法:同余最短路

难度:NOIP

题解:

假设我们将任意一条长度大于k的回路(从2出发回到2)为可行路径,那么任意一条可行路径加上2w一定还是可行路径,所有可行方案中,最短的是k,最长的为 k + 2 * n * w,(n趋近正无穷),(因为我们可以无限循环地走)显然我们不可能求出所有的可行路径来,由于所有可行路径长度中都含有i*2w(i=0,1,2...),我们可以考虑按对2w的余数分块(枚举),这样我们只要求出%2w == 0的最短可行路径,%2w == 1的最短可行路......一直到%2w == 2w - 1的最短可行路径,然后在这2w条可行路径中找一条最短的就是答案了(因为这条一定是所有可行路径中最短的一条)


然后问题就是找到求出%2w同余的所有可行路径中最短的那条了,用dis[i][j]表示从2号点出发到达i,长度%2w为j的最短路径的长度(dis储存的不一定是合法方案,长度可以小于K,因为我们可以最后加x个2w使其刚好大于等于K,并且添加2w以后并不会改变其长度%2w == j 的性质),这个数组可以用dijkstra(spfa)(dijspfa)的算法求出。
 

时间复杂度:O(nmlogn)    m=max(d1,d2)*2

代码如下:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
#define N 15
using namespace std;
ll k;
struct node
{
	int next;
	int to;
	int val;
}edg[N<<1];
int hea[N];
ll dis[5][60005];
int cnt=1;
void init()
{
	memset(hea,-1,sizeof(hea));
	cnt=1;
}
void add(int u,int v,int w)
{
	edg[cnt].next=hea[u];
	edg[cnt].to=v;
	edg[cnt].val=w;
	hea[u]=cnt++;
}
struct nod
{
	int po;
	ll d;
};
bool operator < (nod x,nod y)
{
	return x.d>y.d;
}
int mm;
priority_queueQ;
void dijspfa(int rt)
{
	memset(dis,0x3f3f3f3f,sizeof(dis));
	nod tem;
	tem.po=rt;
	tem.d=0ll;
	Q.push(tem);
	while(!Q.empty())
	{
		nod op;
		op=Q.top();
		Q.pop();
		int u=op.po;
		ll w=op.d;
		if(w>dis[u][w%mm]) continue;
		for(int i = hea[u];i != -1;i=edg[i].next)
		{
			int to=edg[i].to;
			ll ww=w+edg[i].val;
			if(dis[to][ww%mm]>ww)
			{
				dis[to][ww%mm]=ww;
				nod ee;
				ee.po=to;
				ee.d=ww;
				Q.push(ee);
			}
		}
	}
}
int main()
{
	int T,d1,d2,d3,d4;
	scanf("%d",&T);
	while(T--)
	{
		init();
		scanf("%I64d%d%d%d%d",&k,&d1,&d2,&d3,&d4);
		mm=max(d1,d2)*2;
		add(1,2,d1),add(2,1,d1);
		add(2,3,d2),add(3,2,d2);
		add(3,4,d3),add(4,3,d3);
		add(4,1,d4),add(1,4,d4);
		dijspfa(2);
		ll ans=0x7fffffffffffffffll;
	    for(int i = 0;i < mm;i++)
	    {
	        ll dta=k-dis[2][i];
	        if (dta<=0) ans=min(ans,dis[2][i]);
	        else ans=min(ans,dis[2][i]+dta/mm*mm+(dta%mm>0)/*如果为成立,就是1,反之则是0*/*mm);
	    }
	    printf("%I64d\n",ans); 
	}
	return 0 ;
} 

 

你可能感兴趣的:(图论之同余最短路)