3 2 1 3 1
1 2 1
2 3 2
1
咱们直接从起点到终点 BFS,用优先队列存(队列内按距离从大到小排列),依次删除便可,每次 BFS 对一条边均可以选择删或者不删,这就模拟了 DP 的过程,最后若是到达终点直接返回答案便可node
这个是分层最短路的模板题:就是在之前的dis中新加了一维操做次数。ios
dis[i][j]指的是起点为i而且操做了j次的最小值c++
#include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; const int maxn=1e3+100; typedef long long ll; bool vis[maxn][maxn]; int n,m,s,t,k,u,v,w; struct node{ int v,w; }; struct qnode{ int u,d,k;//起点,花费,能够执行的次数 bool friend operator<(qnode a,qnode b){ return a.d>b.d; } }; vector<node>e[maxn]; priority_queue<qnode>q; int dfs(){ qnode a; q.push({s,0,k}); while(!q.empty()){ auto top=q.top(); q.pop(); if(vis[top.u][top.k]) continue; vis[top.u][top.k]=1; if(top.u==t) return top.d; for(auto p:e[top.u]){ if(top.k) q.push({p.v,top.d,top.k-1}); q.push({p.v,top.d+p.w,top.k}); } } } int main(){ cin>>n>>m>>s>>t>>k; for(int i=1;i<=m;i++){ int x,y,z; cin>>x>>y>>z; e[x].push_back({y,z}); e[y].push_back({x,z}); } int ans=dfs(); cout<<ans<<endl; }
code2:ide
#pragma GCC optimize(2) #include<bits/stdc++.h> typedef long long ll; using namespace std; const int N=1e5+100; const ll INF=0x3f3f3f3f3f3f3f3f; struct node{ int from,to;ll val; }num[N]; struct edge{ int v,use;ll val; // bool operator < (const node & a) const{ // return val>a.val; // } }; bool operator < (edge a,edge b){ return a.val>b.val; } int head[N],cnt,m,n,s,t,k; ll dis[1010][1010]; bool vis[1010][1010]; void add(int from,int to,int val){ num[cnt].from=head[from]; num[cnt].to=to; num[cnt].val=val; head[from]=cnt++; } void di(){ priority_queue<edge>p; memset(dis,INF,sizeof dis); p.push((edge){s,0,0}); dis[s][0]; vis[s][0]=1; while(!p.empty()){ edge u=p.top(); p.pop(); for(int i=head[u.v];i!=-1;i=num[i].from){ ll d=num[i].val; int to=num[i].to,use=u.use; if(!vis[to][use+1] && (use+1)<=k && dis[to][use+1]>u.val){ vis[to][use+1]=1; dis[to][use+1]=u.val; p.push((edge){to,use+1,u.val}); } if(!vis[to][use] && dis[to][use]>u.val+d){ dis[to][use]=u.val+d; p.push((edge){to,use,dis[to][use]}); } } } } int main(){ memset(head,-1,sizeof head); scanf("%d%d%d%d%d",&n,&m,&s,&t,&k); for(int i=1;i<=m;i++){int u,v,val; scanf("%d%d%d",&u,&v,&val); add(u,v,val); add(v,u,val); } di(); ll ans=INF; for(int i=0;i<=k;i++){ ans=min(dis[t][i],ans); // cout<<dis[t][i]<<" "; } // cout<<endl; printf("%lld\n",ans); return 0; }
题目连接oop
给你n个点m条边,而后给你起点s和终点t,问你给你k次操做能够使得一条边的权值变为0,问你从s到t的最小值spa
这个题和上一个同样code
#include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; const int maxn=5e4+100; typedef long long ll; bool vis[maxn][110]; int n,m,s,t,k,u,v,w; struct node{ int v,w; }; struct qnode{ int u,d,k;//起点,花费,能够执行的次数 bool friend operator<(qnode a,qnode b){ return a.d>b.d; } }; vector<node>e[200002]; priority_queue<qnode>q; int dfs(){ qnode a; q.push({s,0,k}); while(!q.empty()){ auto top=q.top(); q.pop(); if(vis[top.u][top.k]) continue; vis[top.u][top.k]=1; if(top.u==t) return top.d; for(auto p:e[top.u]){ if(top.k) q.push({p.v,top.d,top.k-1}); q.push({p.v,top.d+p.w,top.k}); } } } int main(){ cin>>n>>m>>k>>s>>t; for(int i=1;i<=m;i++){ int x,y,z; cin>>x>>y>>z; e[x].push_back({y,z}); e[y].push_back({x,z}); } int ans=dfs(); cout<<ans<<endl; }