有任何问题欢迎留言或私聊
题目链接:BZOJ:4289: PA2012 Tax
题意:
给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大
值,求从起点1到点N的最小代价。起点的代价是离开起点的边的边权,终点的代价是进入终
点的边的边权
N<=100000
M<=200000
思路:
看了大神的博客之后,感觉大千世界,无(sang)奇(xin)不(bing)有(kuang)。
这个题的正确姿势是:
- 无向图连边时要拆成两条边,这大家都知道
- 然后把边看成”点”,(优化:)因为不可能每个”点”之间都能连边,所以
- 对除了 1点和 n点之外的点连出去的边(真实边)按权值从小到大排个序,边看作”点”
- 然后 i “点”向 i + 1”点”连一条边值为(化点之前的两条边的权值差);i “点”向 i - 1”点”连一条权值为0LL的边;然后每个”点”和它反向边化成的”点”连一条边值为该边以前权值的边。
5.然后用堆优化的dij跑一遍最短路,求出dis[i]
( dis[i] = 初始点 到 i “点”的最短距离)。
6.最短路初始过程:将原点1连出去的 边看成点 后,加入队列。
7.求值:枚举连向终点n的边,维护ans = minj{dis[i^1] + val[i]}
// i 是边的编号
总结:
这题对于我来说很难,没碰到过这样无(sang)奇(xin)不(bing)有(kuang)的最短路。我真的菜啊!
这种将边看成点,然后奇妙连边构出新图的操作真的秀。
建议大家有机会自己试试这题,把代码搞懂之后,试着不看代码,自己一步步从头敲出来,然后再思考一发。
虽然现在a了这题,实话实说,一段时间过后,我肯定不能再a掉。但是思路应该是肯定了解的。码力还很差呀。加油吧!
#include<bits/stdc++.h>
#define fuck(x) printf("*%d\n",(x))
using namespace std;
typedef long long LL;
typedef pair<LL, int> pii;
const int N = 1e5+5;
struct lh{
int to;
LL val;
int nex;
lh(){}
lh(int a,LL b,int c){to=a,val=b,nex=c;}
friend bool operator<(const lh &a,const lh &b){
return a.val<b.val;
}
}cw[N*10],edge[N*10];
int head[N*5],vis[N*5];
LL dis[N*5];
std::vector<pii> g[N*5];
int n,m,tot;
void add(int x,int y,LL z){
cw[++tot]=lh(y,z,head[x]);
head[x]=tot;
cw[++tot]=lh(x,z,head[y]);
head[y]=tot;
}
void init(){
memset(head,-1,sizeof(head));
tot=-1;
for(int i=0;i<5*N;++i)g[i].clear();
}
void dij(){
priority_queue<pii,vector<pii> ,greater<pii> >Q;
while(!Q.empty())Q.pop();
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
for(int i=head[1];~i;i=cw[i].nex){
dis[i]=cw[i].val;
//vis[i]=1;
Q.push(make_pair(dis[i],i));
}
while(!Q.empty()){
pii a=Q.top();Q.pop();
int u=a.second;
if(vis[u])continue;
vis[u]=1;
for(int i=g[u].size()-1;i>=0;--i){
int v=g[u][i].second;
if(vis[v])continue;
if(dis[v]>dis[u]+g[u][i].first){
dis[v]=dis[u]+g[u][i].first;
Q.push(make_pair(dis[v],v));
}
}
}
}
int main(int argc, char const *argv[]){
while(~scanf("%d%d",&n,&m)){
init();
int x,y;
LL z;
for(int i=0;i<m;++i){
scanf("%d%d%lld",&x,&y,&z);
add(x,y,z);
}
for(int ii=2,tp=0;ii<n;tp=0,++ii){
for(int e=head[ii];~e;e=cw[e].nex){
edge[++tp].to=e;edge[tp].val=cw[e].val;
}
sort(edge+1,edge+1+tp);
for(int i=1;i<=tp;++i){
if(i!=1)g[edge[i].to].push_back(make_pair(0LL,edge[i-1].to));
if(i!=tp)g[edge[i].to].push_back(make_pair(edge[i+1].val-edge[i].val,edge[i+1].to));
g[edge[i].to^1].push_back(make_pair(edge[i].val,edge[i].to));
}
}
dij();
LL ans=0x3f3f3f3f3f3f3f3f;
for(int i=head[n];~i;i=cw[i].nex){
ans=min(ans,dis[i^1]+cw[i].val);
}
printf("%lld\n",ans );
}
return 0;
}