最短缩减路径
最短缩减路径
给定一张无向图,你可以让任意一条边的权值减半,求起点到终点的最短路径。
点数 \(\le 500\);边数 \(\le 50000\);\(1\le\) 边权 \(\le 500000\),且均为偶数。
本题有两种思路:
- 分层图,就只有一条边,只需要分两层,是比较简单的模型应用。
- 计算从起点、终点到其他所有点的距离,然后枚举中间的任意一条边(方向不同视作不同的边),计算三部分:起点到边一端、这条边的权值减半、边另一端到终点,由于是无向图,所以从终点到其他所有点的距离等价于从其他所有点到终点的距离,把三部分相加即可。
分层图
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while
const int N=1010,M=6*50010;
int n,m,sta,en,dis[N];
int h[N],e[M],ne[M],idx,w[M];//don't forget memset h!
bool st[N];
struct node{
int x,dis;
bool operator<(const node &y)const{
return dis>y.dis;
}
};
priority_queue<node>q;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra(int s){
memset(dis,0x3f,n*4+4);
memset(st,0,n+1);
dis[s]=0;
q.push({s,0});
while(!q.empty()){
auto t=q.top();q.pop();
int x=t.x,dist=t.dis;
// printf("x=%d,dis={%d}\n",x,dist);
if(st[x])continue;
if(x==en){
printf("%d",dis[x]);
return;
}
st[x]=1;
Ed{
int j=e[i];
if(dis[j]>dist+w[i]){
dis[j]=dist+w[i];
q.push({j,dis[j]});
}
}
}
// E(i, n)printf("%d ",dis[i]);
// puts("");
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
memset(h,-1,n*8+4);
E(i, m){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
add(a,b+n,c>>1),add(b,a+n,c>>1);
add(a+n,b+n,c),add(b+n,a+n,c);
}
scanf("%d%d",&sta,&en);
if(sta==en)return puts("0"),0;
en+=n;
n<<=1;
dijkstra(sta);
return 0;
}
枚举边
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define Ed for(int i=h[x];~i;i=ne[i])
#define Ls(i,l,r) for(int i=l;i<r;++i)
#define Rs(i,l,r) for(int i=l;i>r;--i)
#define Le(i,l,r) for(int i=l;i<=r;++i)
#define Re(i,l,r) for(int i=l;i>=r;--i)
#define L(i,l) for(int i=0;i<l;++i)
#define E(i,l) for(int i=1;i<=l;++i)
#define W(t) while(t--)
#define Wh while
const int N=510,M=2*50010;
int n,m,sta,en,dis[N],dis2[N];
int h[N],e[M],ne[M],idx,w[M];//don't forget memset h!
bool st[N];
struct node{
int x,dis;
bool operator<(const node &y)const{
return dis>y.dis;
}
};
priority_queue<node>q;
void add(int a,int b,int c){
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
void dijkstra(int s,int dis[]){
memset(dis,0x3f,n*4+4);
memset(st,0,n+1);
dis[s]=0;
q.push({s,0});
while(!q.empty()){
auto t=q.top();q.pop();
int x=t.x,dist=t.dis;
// printf("x=%d,dis={%d}\n",x,dist);
if(st[x])continue;
st[x]=1;
Ed{
int j=e[i];
if(dis[j]>dist+w[i]){
dis[j]=dist+w[i];
q.push({j,dis[j]});
}
}
}
// E(i, n)printf("%d ",dis[i]);
// puts("");
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
memset(h,-1,n*4+4);
E(i, m){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c),add(b,a,c);
}
scanf("%d%d",&sta,&en);
if(sta==en)return puts("0"),0;
dijkstra(sta,dis);
dijkstra(en,dis2);
int ans=1e9;
L(i, idx){
ans=min(ans,dis[e[i^1]]+(w[i]>>1)+dis2[e[i]]);
}
printf("%d",ans);
return 0;
}