链接
背景
(CCF) (NOI) (2012) 北京市代表队冬令营, (Luogu) (P4822/BZOJ2662)
题意
给定 (n) 个点, (m) 条边的两个端点 (x,y) ,规定一条路径上最多可以使得 (k) 条边变成原边权的一半(保证原边权是偶数) 。求 (1) 到 (n) 的最短路径长度。若不能到达则输出 (-1) 。
解法
分层图最短路模板。
由于可以 (k) 次边权减半,建 (k) 层图(假定变成 (0) 的边数越多图越高)即可。
注意每条边在每一层上连一遍,然后 (x) 向高一层的 (y) 连 (0) 边, (y) 向高一层的 (x) 连 (w/2) 边。
从 (1) 号点开始 (dijkstra) ,答案是所有层上第 (n) 个点的最短路的最小值。
记得判没更新过的 (ans) 误解。
代码
$View$ $Code$
```cpp
#include
using namespace std;
inline int read()
{
int ret=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ret=(ret<<1)+(ret<<3)+ch-'0';
ch=getchar();
}
return ret*f;
}
const int inf=0x3f3f3f3f;
int n,m,k,s,t,u,v,w;
int dis[3005],ans=inf;
int num,head[3005];
bool vis[3005];
struct edge
{
int ver,nxt,w;
}e[300005];
inline void adde(int u,int v,int w)
{
e[++num].ver=v;
e[num].w=w;
e[num].nxt=head[u];
head[u]=num;
}
void dijkstra(int s)
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
priority_queue > q;
dis[s]=0;
q.push(make_pair(0,s));
while(!q.empty())
{
int x=q.top().second;
q.pop();
if(vis[x])
continue;
vis[x]=1;
for(register int i=head[x];i;i=e[i].nxt)
{
int y=e[i].ver,w=e[i].w;
if(dis[x]+w