转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题意:给出a个村庄,b个城堡,村庄的标号为1……a,城堡的标号为a+1……a+b。然后有m条无向边,每条边有个距离。某个人打算从a+b到1,然后他有一双神奇的鞋子,可以用k次,每次最多连续跑L。而且穿着鞋子的时候不能穿过城堡,到达城堡的时候只能停下,而且不能停留在路中间。只要停下来,就相当于用了一次鞋子。
今天做完TC,对于div1的450,是一个新接触的。在spfa中跑DP。有效的解决了图上DP的后效性问题。
yobobobo之后推荐了这个题,主要还是受TC的影响,才能想到正解。
首先预处理下穿鞋子跑一次的情况。
枚举所有点为起点,然后预处理从这个点穿着鞋子跑到达每一个点的最短距离。
而且注意:不能穿过城堡
在SPFA的时候,不会把城堡入队(除了城堡是起点)
之后dp[i][j]表示在i点时,鞋子还剩j次的最短距离。
DP过程扔进spfa里更新就行了。
对于每一个点,更新情况有两种。
首先不考虑鞋子,步行到下一个地方。
考虑用一次鞋子,枚举所有的点,进行转移。
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#include<set>
#include<stack>
#include<string>
#include<ctime>
#include<queue>
#define inf 0x3f3f3f3f
#define M 10000005
#define N 40005
#define maxn 210005
#define eps 1e-8
#define zero(a) fabs(a)<eps
#define Min(a,b) ((a)<(b)?(a):(b))
#define Max(a,b) ((a)>(b)?(a):(b))
#define pb(a) push_back(a)
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define LL long long
#define MOD 1000000007
#define sqr(a) ((a)*(a))
#define Key_value ch[ch[root][1]][0]
#define test puts("OK");
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#define HASH1 1331
#define HASH2 10001
#define C 240
#define vi vector<int>
#define TIME 10
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
struct Edge{
int v,w,next;
}e[10005];
int t,a,b,m,l,k;
int start[105],tot;
int dist[105][105];
int dp[105][15];
void _add(int u,int v,int w){
e[tot].v=v;e[tot].w=w;
e[tot].next=start[u];
start[u]=tot++;
}
void add(int u,int v,int w){
_add(u,v,w);
_add(v,u,w);
}
void Init(){
queue<int>que;
bool in[105];
mem(dist,0x3f);
for(int i=1;i<=a+b;i++){
while(!que.empty()) que.pop();
mem(in,false);
que.push(i);
in[i]=true;
dist[i][i]=0;
while(!que.empty()){
int u=que.front();
que.pop();
in[u]=false;
for(int r=start[u];r!=-1;r=e[r].next){
int v=e[r].v,w=e[r].w;
if(dist[i][v]>dist[i][u]+w){
dist[i][v]=dist[i][u]+w;
if(v<=a&&in[v]==false){
in[v]=true;
que.push(v);
}
}
}
}
}
}
int main(){
scanf("%d",&t);
while(t--){
mem(start,-1);
tot=0;
scanf("%d%d%d%d%d",&a,&b,&m,&l,&k);
for(int i=0;i<m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
Init();
bool in[105];
mem(in,false);
mem(dp,0x3f);
queue<int>que;
que.push(a+b);
in[a+b]=true;
dp[a+b][k]=0;
while(!que.empty()){
int u=que.front();
que.pop();
in[u]=false;
for(int i=0;i<=k;i++){
for(int r=start[u];r!=-1;r=e[r].next){
int v=e[r].v,w=e[r].w;
if(dp[v][i]>dp[u][i]+w){
dp[v][i]=dp[u][i]+w;
if(in[v]==false){
in[v]=true;
que.push(v);
}
}
}
if(!i) continue;
for(int v=1;v<=a+b;v++){
if(v!=u&&dist[u][v]<=l){
if(dp[v][i-1]>dp[u][i]){
dp[v][i-1]=dp[u][i];
if(in[v]==false){
in[v]=true;
que.push(v);
}
}
}
}
}
}
int ans=inf;
for(int i=0;i<=k;i++)
ans=min(ans,dp[1][i]);
printf("%d\n",ans);
}
return 0;
}