题目链接:https://nanti.jisuanke.com/t/31001
题目大意:给出一个含有n个点m条边的带权有向图,求1号顶点到n号顶点的最短路,可以使<=k条任意边的权值变为0。
样例输入 复制
1 5 6 1 1 2 2 1 3 4 2 4 3 3 4 1 3 5 6 4 5 2
样例输出 复制
3 解题思路:可以用两种做法,不过都差不多,应该算是同一种思路的不同写法。第一种是在建图时,将一个点拆成k个层次的点,应该总共有k+1层,每个相同层次的点按输入的边权连接,每个点可以向它能连接到的点的下一个层次连接一条边权为0的边,这样你每使一条边权值变为0,即相当于走到了下一层图,永远不能走回,当走到第k+1层图时即不能使用了,在这个含有k+1层图的大图里跑下最短路就可以得出答案了附上代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn=2200007; const ll inf=0x3f3f3f3f; struct qnode{ int u; ll dis; bool operator<(const qnode &a)const{ return dis>a.dis; } qnode(int a,ll b) { u=a; dis=b; } }; struct node{ int v,w,next; }edge[2*maxn]; int n,m,k,tot=0,head[maxn]; ll dis[maxn]; void add(int u,int v,int w) { edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } void init() { tot=0; memset(head,-1,sizeof(head)); } void dij() { priority_queue<qnode> que; memset(dis,inf,sizeof(dis)); dis[1]=0; que.push(qnode(1,0)); while(!que.empty()) { int u=que.top().u; que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v,w=edge[i].w; if(dis[v]>dis[u]+w) { dis[v]=dis[u]+w; que.push(qnode(v,dis[v])); } } } } int main() { int T; scanf("%d",&T); while(T--) { init(); scanf("%d%d%d",&n,&m,&k); for(int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); for(int j=0;j<=k;j++) { add(u+j*n,v+j*n,w); //同一层次的点用输入边权相连 if(j!=k) add(u+j*n,v+(j+1)*n,0); //不同层次的点用0权值相连 } } if(k>=m) { printf("0\n"); continue; } ll ans=inf; dij(); for(int i=0;i<=k;i++) ans=min(ans,dis[n+i*n]); printf("%lld\n",ans); } return 0; }
第二种是用最短路+dp思想,再开一维数组记录已经使用了几次使边的权值为0,也是跑下最短路就可以了。
附上代码:
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+7; const long long inf=0x3f3f3f3f; struct node{ int v,w,next; }edge[2*maxn]; struct qnode{ int u,k; long long dis; bool operator<(const qnode &a)const{ return dis>a.dis; } qnode(int a,int b,long long c) { u=a; k=b; dis=c; } }; int n,m,k,tot=0,head[maxn]; long long dis[maxn][15]; void add(int u,int v,int w) { edge[tot].v=v; edge[tot].w=w; edge[tot].next=head[u]; head[u]=tot++; } void init() { tot=0; memset(head,-1,sizeof(head)); } long long dijkstra() { priority_queue<qnode> que; for(int i=1;i<=n;i++) { for(int j=0;j<=k;j++) { dis[i][j]=inf; } } que.push(qnode(1,0,0)); dis[1][0]=0; while(!que.empty()) { int u=que.top().u,tempk=que.top().k; if(u==n) return dis[u][tempk]; que.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v,w=edge[i].w; if(dis[u][tempk]+w<dis[v][tempk]) //同一层的最短路 { dis[v][tempk]=dis[u][tempk]+w; que.push(qnode(v,tempk,dis[v][tempk])); } if(tempk<k) { if(dis[u][tempk]<dis[v][tempk+1]) //如果将这条边权值变为0,就会进入tempk+1层 { dis[v][tempk+1]=dis[u][tempk]; que.push(qnode(v,tempk+1,dis[v][tempk+1])); } } } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); init(); for(int i=0;i<m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w); } printf("%lld\n",dijkstra()); } return 0; }
原文地址:https://www.cnblogs.com/zjl192628928/p/9744404.html
时间: 2024-11-10 17:24:58