题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2763
中文题不解释题意了
思路:我们设置dis[i][k]表示走到第i号点,免费经过了k条边的最短路。
对于我们当前找到的终点,尝试起点的状态去更新,不选择此条边免费的状态和选择此条边免费的状态,再将这两个状态压入队列去更新可以到达的其他状态。
代码(原oj好像不能注册就没有再注册去提交,样例可以过就是了)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
#define LL long long
const int MOD=1e9+7;
const int inf=0x3f3f3f3f;
const LL MAX_N=10005;
const LL MAX_M=100005;
#define MEF(x) memset(x,-1,sizeof(x))
#define ME0(x) memset(x,0,sizeof(x))
#define MEI(x) memset(x,inf,sizeof(x))
struct D
{
LL i,k;
};
struct LX
{
LL st,ed,di,next;
}lx[MAX_M];
LL first[MAX_N];
LL dis[MAX_N][15];
LL vis[MAX_N][15];
LL cnt;
void add(LL s,LL e,LL d)
{
lx[++cnt].st=s;
lx[cnt].ed=e;
lx[cnt].di=d;
lx[cnt].next=first[s];
first[s]=cnt;
}
void spfa(LL st,LL ed,LL k)
{
queue<D> q;
D d;
MEI(dis);
ME0(vis);
d.i=st;d.k=0;
dis[st][0]=0;
q.push(d);
vis[st][0]=1;
while(!q.empty())
{
D d=q.front();
LL x=d.i,kk=d.k;
q.pop();
vis[x][kk]=0;
for(LL i=first[x];i!=-1;i=lx[i].next)
{
LL y=lx[i].ed;
if(dis[y][kk]>dis[x][kk]+lx[i].di)
{
dis[y][kk]=dis[x][kk]+lx[i].di;
if(!vis[y][kk])
{
D dd;
dd.i=y;dd.k=kk;
q.push(dd);
vis[y][kk]=1;
}
}
if(kk+1<=k)
{
if(dis[y][kk+1]>dis[x][kk])
{
dis[y][kk+1]=dis[x][kk];
if(!vis[y][kk+1])
{
D dd;
dd.i=y;dd.k=kk+1;
q.push(dd);
vis[y][kk+1]=1;
}
}
}
}
}
printf("%lld\n",dis[ed][k]);
}
int main()
{
LL n,m,k,st,ed,s,e,d;
scanf("%lld%lld%lld%lld%lld",&n,&m,&k,&st,&ed);
cnt=0;
MEF(first);
for(int m1=1;m1<=m;m1++)
{
scanf("%lld%lld%lld",&s,&e,&d);
add(s,e,d);
add(e,s,d);
}
spfa(st,ed,k);
return 0;
}
题目链接:https://nanti.jisuanke.com/t/31001
题意:在一个n个点m条边的图中求1号点到n号店的最短距离,你有k次机会使某条路的权值变成0
输入:
第一行一个T,表示T个样例
接下来一行输入n,m,k(n,m,k意思如题意)
接下来m行u,v,c(u表示起点,v表示终点,c表示距离)单向边
思路:优先队列优化的dijstra,不同的是改变了dis数组的意义,我们设置dis[i][k]表示走到第i号点,免费经过了k条边的最短路
个人感觉用到了dp的思想,每一次更新状态时都更新两次,一次是选择当前边不变成0,另一个是选择当前边变成0,把更新的状态推进队列用来更新其他状态。
AC代码:(spfa好像会被卡时间,出题人的锅。。。。。。)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
#define LL long long
const int MOD=1e9+7;
const int inf=0x3f3f3f3f;
const LL MAX_N=100005;
const LL MAX_M=200005;
#define MEF(x) memset(x,-1,sizeof(x))
#define ME0(x) memset(x,0,sizeof(x))
#define MEI(x) memset(x,inf,sizeof(x))
struct D
{
LL i,k,diss;
};
struct LX
{
LL st,ed,di,next;
}lx[MAX_M];
LL first[MAX_N];
LL dis[MAX_N][15];
LL vis[MAX_N][15];
LL cnt;
void add(LL s,LL e,LL d)
{
lx[++cnt].st=s;
lx[cnt].ed=e;
lx[cnt].di=d;
lx[cnt].next=first[s];
first[s]=cnt;
}
struct cmp
{
bool operator()(const D a,const D b)
{
return a.diss>b.diss;
}
};
void dijstra(LL st,LL ed,LL k)
{
priority_queue<D,vector<D>,cmp> q;
MEI(dis);
ME0(vis);
D d;
d.i=st;d.k=0;d.diss=0;
dis[st][0]=0;
q.push(d);
while(!q.empty())
{
D dd=q.top();
q.pop();
LL x=dd.i,kk=dd.k;
if(vis[x][kk])
{
continue;
}
vis[x][kk]=1;
for(LL i=first[x];i!=-1;i=lx[i].next)
{
int y=lx[i].ed;
if(!vis[y][kk]&&dis[y][kk]>dis[x][kk]+lx[i].di)
{
dis[y][kk]=dis[x][kk]+lx[i].di;
D ddd;
ddd.i=y;ddd.k=kk;ddd.diss=dis[y][kk];
q.push(ddd);
}
if(kk+1<=k&&!vis[y][kk+1]&&dis[y][kk+1]>dis[x][kk])
{
dis[y][kk+1]=dis[x][kk];
D ddd;
ddd.i=y;ddd.k=kk+1;ddd.diss=dis[y][kk+1];
q.push(ddd);
}
}
}
printf("%lld\n",dis[ed][k]);
}
int main()
{
LL t;
scanf("%lld",&t);
for(LL t1=1;t1<=t;t1++)
{
LL n,m,k,s,e,d;
scanf("%lld%lld%lld",&n,&m,&k);
cnt=0;
MEF(first);
for(int m1=1;m1<=m;m1++)
{
scanf("%lld%lld%lld",&s,&e,&d);
add(s,e,d);
}
dijstra(1,n,k);
}
return 0;
}
参考博客:https://blog.csdn.net/qq_36693533/article/details/78466623