题目链接:https://vjudge.net/problem/Gym-101630J
转自:https://blog.csdn.net/TelmaZzzz/article/details/100177172utm_source=blogxgwz0
题意:一个无向图,给一个k,求从1到n的最短路。最短路的花费是如果经过的边数<=k,就是经过的边的总权值和,如果>k,是经过的边前k大的权值和。
思路:假如所求的最短代价路径的边数大于k,枚举所有边,假设该边为所求最小代价的路径中前k大的最小边,将图中所有边权减去枚举到的边权值(出现负数置0)再跑一遍最短路,最后再和初始的最短路比较一下即可。
证明:
假如枚举到的边比当前边小,那答案必定是 上述计算得到的答案+尾部没被置0的值必定大于上述计算所求
假如枚举到的边比当前边大,那答案相当于把原来后几位比当前边小的边多加了变成了当前边,答案肯定也会变大。
先贴一下bfs的错误代码,第12组答案错误,求指点
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <cstring>
#include <stack>
using namespace std;
long long n,m,k,vis[3005];
long long ans=1e18;
struct EDGE
{
long long u;
long long w;
};
vector <EDGE> g[3005];
struct NODE
{
vector <long long >g;
long long cur;
long long sz,x;
NODE()
{
g.clear();
cur=sz=0;
}
};
void bfs()
{
queue<NODE> q;
NODE u,t;
u.x=1;
q.push(u);
long long v;
while(!q.empty())
{
u=q.front();
q.pop();
vis[u.x]=1;
long long l=g[u.x].size();
for(long long i=0; i<l; i++)
{
v=g[u.x][i].u;
if(!vis[v])
{
if(v!=n)
{
t=u;
t.g.push_back(g[u.x][i].w);
t.sz++;
t.x=v;
t.cur+=g[u.x][i].w;
q.push(t);
}
else
{
t=u;
t.g.push_back(g[u.x][i].w);
t.sz++;
t.cur+=g[u.x][i].w;
if(t.sz<=k)
{
ans=min(ans,t.cur);
}
else
{
sort(t.g.begin(),t.g.end(),greater<long long > ());
long long tep=0;
for(long long j=0; j<k; j++)
{
tep+=t.g[j];
}
ans=min(ans,tep);
}
}
}
}
}
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&k);
EDGE e;
for(long long i=0; i<m; i++)
{
long long x,y;
long long w;
scanf("%lld%lld%lld",&x,&y,&w);
e.u=y;
e.w=w;
g[x].push_back(e);
e.u=x;
g[y].push_back(e);
}
bfs();
printf("%lld\n",ans);
return 0;
}
正确代码
#include <bits/stdc++.h>
using namespace std;
const long long maxn=3005;
const long long inf=1e18;
struct Edge
{
long long from,to,dist;
Edge(long long u,long long v,long long d):from(u),to(v),dist(d)
{
}
};
struct heapnode
{
long long d,u;
bool operator <(const heapnode &r)const
{
return d>r.d;
}
};
struct Dijkstra
{
long long n,m;
vector <Edge> edges;//保存所有边
vector <long long > G[maxn];//只保存边的编号
bool done[maxn];//访问标记
long long d[maxn];//到每个点的距离
void init(long long n)//传参为顶点数
{
this->n=n;
for(long long i=0; i<=n; i++)
{
G[i].clear();
}
edges.clear();
}
void addedge(long long from,long long to,long long dist)
{
edges.push_back(Edge(from,to,dist));
m=edges.size();
G[from].push_back(m-1);
}
void dijkstra (long long s)
{
priority_queue<heapnode> q;
for(int i=0; i<=n; i++)
d[i]=inf;
d[1]=0;
memset(done,0,sizeof(done));
q.push((heapnode)
{
0,1
});
while(!q.empty())
{
heapnode x=q.top();
q.pop();
long long u=x.u;
if(done[u])
continue;
done[u]=true;
for(long long i=0; i<G[u].size(); i++)
{
Edge &e=edges[G[u][i]];
long long c=e.dist-s;
c=max((long long)0,c);
if(d[e.to]>d[u]+c)
{
d[e.to]=d[u]+c;
q.push(heapnode{d[e.to],e.to});
}
}
}
}
} dij;
long long a[maxn];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
dij.n=n;
for(int i=0; i<m; i++)
{
long long x,y;
scanf("%lld%lld%lld",&x,&y,&a[i]);
dij.addedge(x,y,a[i]);
dij.addedge(y,x,a[i]);
}
dij.dijkstra(0);
long long ans=dij.d[n];
for(int i=0; i<m; i++)
{
dij.dijkstra(a[i]);
ans=min(ans,dij.d[n]+k*a[i]);
}
printf("%lld\n",ans);
return 0;
}