1. 程式人生 > >HDU6071 Lazy Running

HDU6071 Lazy Running

pri names scanf code 最小 出發 cst pen 標準

鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6071

挺晚了,還是決定寫一下題解~~~

題意:給你四個點,組成一個圈,求從2出發再回到2的所有路徑中大於K的最小值;

思路:其實跟前一篇大容量背包一樣利用同余系最短路求;

可以這麽理解,我對滿足要求的所有路徑分類,標準是模m的值為j(0=<j<m)的所有路徑分到一組,而dis[i][j]表示滿足從1到i模m為j的最小

路徑,因為我們求的是最短路徑,對於一組同余系,我記錄最小的解即可,m是從1出來的兩條邊中最短的那條邊的二倍,之所以是二倍

,因為我要滿足一個環,使原來的解加上一個環依舊是一個解,最後把dis[1][0~m-1]的數都變成大於k得數,從中取最小值即可;為什麽

結果一定是正解呢?因為發現在這我把所有的解變成了dis[1][0~m-1]+x*m的形式了,那我從dis[1][0~m-1]出發,一定可以找到解空間的

所有情況,那我找出來的最小值必然是正解了;

代碼:

技術分享

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
typedef long long LL;
const int maxn=6e4+10;
bool vis[5][maxn];
LL dis[
5][maxn],G[5][5]; struct node { int p,j; node(int _p,int _j):p(_p),j(_j){} }; void spfa(int s,int m) { memset(vis,0,sizeof vis); memset(dis,0x3f,sizeof dis); queue<node>q; q.push(node(1,0)); dis[1][0]=0; vis[1][0]=true; while(!q.empty()) { node tn=q.front(); q.pop();
int v=tn.p,j=tn.j; vis[v][j]=false; for(int i=-1;i<2;i+=2) { int tv=(v+i+4)%4; LL d=dis[v][j]+G[v][tv]; if(dis[tv][d%m]>d) { dis[tv][d%m]=d; if(!vis[tv][d%m]) { q.push(node(tv,d%m)); vis[tv][d%m]=true; } } } } } int main() { //freopen("input.txt","r",stdin); int T; for(scanf("%d",&T);T;T--) { LL k;scanf("%lld",&k); for(int i=0;i<4;i++) { scanf("%lld",&G[i][(i+1)%4]); G[(i+1)%4][i]=G[i][(i+1)%4]; } int m=2*min(G[1][0],G[1][2]); spfa(1,m); LL ans=((k-1)/m+1)*m; for(int i=0;i<m;i++) { LL tmp=dis[1][i]>k?dis[1][i]:((k-dis[1][i]-1)/m+1)*m+dis[1][i]; ans=min(ans,tmp); } printf("%lld\n",ans); } return 0; }

HDU6071 Lazy Running