P9504题解
题目链接 评测记录
分享一个分层图的做法。
由题意可知本题的所需生命值在路径中是单调不减的,题目本质是一个最短路。
从起点开始跑的话由于不知道魔力值和生命值,不好搞,但是最后到达终点时的魔力值和生命值一定为
但只当做一个
如果我们将魔力和所需生命值同时记录并松弛连接的节点,该题最短路做法就是正确的。
于是我们可以想到分层图,来记录每层的魔力值。
由于边权的范围比较小,可以考虑以此为层数建分层图。
当然分层图建多了也没有关系,因为这也符合题意,所需的血量在一条路径上是单调不减的。
可以尝试下建最大的
最后直接遍历每层的
注意数据范围。
代码如下。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN=2e4+10,MAXM=4e4+10,INF=0x3f3f3f3f,MAXW=100+5;
struct EDGE
{
int v,w,nxt;
}edge[(MAXM<<1)*MAXW];
struct node
{
int u,dis;
bool operator<(const node a)const
{
return dis>a.dis;
}
};
priority_queue<node> q;
int n,m,cnt,moli[MAXN*MAXW],head[MAXN*MAXW],dis[MAXN*MAXW]/*dis表示生命值*/;
bool vis[MAXN*MAXW];
inline int read()
{
int x=0;
char ch=getchar();
while(ch<'0'||ch>'9'){ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
void add(int u,int v,int w)
{
++cnt;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].nxt=head[u];
head[u]=cnt;
}
void dijkstra(int s)
{
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push((node){s,dis[s]});
while(!q.empty())
{
node a=q.top();q.pop();
int u=a.u;
if(vis[u])continue;
vis[u]=1;
int tmoli=moli[u]+1;
for(int i=head[u];i;i=edge[i].nxt)
{
int v=edge[i].v,w=edge[i].w;
int adis=w/tmoli,tdis=adis+dis[u];
if(tdis<dis[v])
{
dis[v]=tdis;
moli[v]=tmoli;
q.push((node){v,dis[v]});
}
}
}
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int s,t;
n=read();m=read();s=read();t=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
for(int j=1;j<MAXW;j++)
{
add(u+(j-1)*n,v+n*j,w);
add(v+(j-1)*n,u+n*j,w);
}
}
dijkstra(t);
int ans=INF;
for(int i=0;i<MAXW;i++)
{
ans=min(ans,dis[s+i*n]);
}
cout<<ans;
return 0;
}