一个分层图板子题,但dp式略有不同。
还是设为从经过条优惠边时的最短路。dp式:
指所有终点为的边。
但这个题还有一个限制:卡片只能在一条边作用一次。其实这个限制我们在代码中不用另外判断。由于边权为正,所以在一条边上使用多次肯定不如在多条边上使用一次更优。因为在一条边上使用多次卡片,总优惠还是,对于此题而言,效果不会累加。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#define ri register int
using namespace std;
const int NMAXN=60,MMAXN=2020,INF=1310668019;
int n,m,k,u[MMAXN],v[MMAXN],w[MMAXN],fst[MMAXN],nxt[MMAXN],dis[MMAXN][NMAXN];
bool book[NMAXN];
struct node{
int num,c;
};
priority_queue<node>Q;
bool operator<(const node &a,const node &b)
{
return a.c > b.c;
}
void Dijkstra(int cnt)
{
memset(book,0,sizeof(book));
for(ri i=1;i<=n;i++) dis[i][cnt]=INF;
dis[1][cnt]=0;
Q.push((node){1,0});
while(!Q.empty())
{
int x=Q.top().num; Q.pop();
if(book[x]) continue;
book[x]=1;
for(ri k=fst[x];k>0;k=nxt[k])
{
if(cnt==0&&dis[v[k]][0]>dis[u[k]][0]+w[k])
{
dis[v[k]][0]=dis[u[k]][0]+w[k];
Q.push((node){v[k],dis[v[k]][0]});
}
if(cnt>0&&dis[v[k]][cnt]>dis[u[k]][cnt-1]+w[k]/2)
{
dis[v[k]][cnt]=dis[u[k]][cnt-1]+w[k]/2;
Q.push((node){v[k],dis[v[k]][cnt]});
}
if(cnt>0&&dis[v[k]][cnt]>dis[u[k]][cnt]+w[k])
{
dis[v[k]][cnt]=dis[u[k]][cnt]+w[k];
Q.push((node){v[k],dis[v[k]][cnt]});
}
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
m <<=1;
for(ri i=1;i<=m;i+=2)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
nxt[i]=fst[u[i]],fst[u[i]]=i;
u[i+1]=v[i],v[i+1]=u[i],w[i+1]=w[i];
nxt[i+1]=fst[u[i+1]],fst[u[i+1]]=i+1;
}
for(ri i=0;i<=k;i++) Dijkstra(i);
cout<<dis[n][k];
return 0;
}