您的位置:首页 > 其它

bzoj 4398 福慧双修 题解

2016-01-08 20:34 417 查看
卡了一晚上啊

首先我们要跑一边整张图的spfa,记录每个点是从哪条边出去的(pre数组)

这里记录的不是前驱边,而是和原点相连的第一个点编号,因为不能走重复边所以才要记录这个,以免刚刚出去又原路返回

那么有一个朴素思路:spfa每一个1点连出去的点

事实上这样是会T的。。。

从这里改进,我们发现上面那种方法走了很多重复的工作,每一次spfa其实是非常类似的

那么我们可以优化一下这个过程:建一张新图跑spfa

这张新图这样建:建立新汇点n+1,设当前边(u,v,w)

1.原点连出的{

pre[v]!=v的话,连1,v,w

否则不连

}

2.连向原点的{

pre[u]!=u 直接用dis[u]+w更新答案

否则连u,n+1,w

}

3.其他的,如果pre[u]==pre[v]从一到v建dis[u]+w的边

否则保留原边

那么新图的最短路就是答案

某个T掉了的

//Copyright(c)2015 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
#define o(e) ((((e)-1)^1)+1)
#define inc(a) a++;if(a==100000)a=1;
#define inf 1000000000
using namespace std;
inline void splay(int &v){
v=0;char c=0;int p=1;
while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
v*=p;
}
struct Edge{
int to,next,len;
}edge[200010];
int first[100010],size;
int dis[40010],dl[100010];
bool exsit[40010];
void addedge(int x,int y,int z){
size++;
edge[size].to=y;
edge[size].next=first[x];
first[x]=size;
edge[size].len=z;
}
int head,tail;
int spfa(int now,int lim){
head=0,tail=1;
memset(dis,63,sizeof dis);
dis[now]=0,dl[1]=now;
while(head!=tail){
inc(head);int v=dl[head];exsit[v]=false;
for(int u=first[v];u;u=edge[u].next){
if(edge[u].len+dis[v]<dis[edge[u].to] && u!=lim){
dis[edge[u].to]=edge[u].len+dis[v];
if(!exsit[edge[u].to]){
exsit[edge[u].to]=true;
inc(tail);dl[tail]=edge[u].to;
}
}
}
}
return dis[1];
}
int main(){
freopen("xxx.in","r",stdin);
freopen("xxx.out","w",stdout);
int n,m;splay(n),splay(m);
for(int i=1;i<=m;i++){
int s,e,l,r;
splay(s),splay(e),splay(l),splay(r);
addedge(s,e,l);addedge(e,s,r);
}
int ans=inf;
for(int u=first[1];u;u=edge[u].next){
ans=min(ans,spfa(edge[u].to,o(u))+edge[u].len);
}
cout<<ans<<endl;
}
A了的

//Copyright(c)2015 liuchenrui
#include<cstdio>
#include<ctime>
#include<iostream>
#include<algorithm>
#include<cstring>
#define o(e) ((((e)-1)^1)+1)
#define inc(a) a++;if(a==100000)a=1;
#define inf 1000000000
using namespace std;
inline void splay(int &v){
v=0;char c=0;int p=1;
while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
v*=p;
}
struct Edge{
int to,next,len,from;
}edge[300010],e[300010];
int first[100010],size;
int dis[40010],dl[100010];
bool exsit[40010];
int pre[40010];
int f[40010],s;
int n,m;
void addedge(int x,int y,int z){
size++;
edge[size].to=y;
edge[size].next=first[x];
first[x]=size;
edge[size].len=z;
edge[size].from=x;
}
void add(int x,int y,int z){
s++;
e[s].to=y;
e[s].next=f[x];
f[x]=s;
e[s].len=z;
fprintf(stderr,"%d %d %d\n",x,y,z);
}
int head,tail,ans=inf;
void spfa(){
while(head!=tail){
inc(head);int v=dl[head];exsit[v]=false;
for(int u=first[v];u;u=edge[u].next){
if(edge[u].len+dis[v]<dis[edge[u].to]){
dis[edge[u].to]=edge[u].len+dis[v];
pre[edge[u].to]=pre[v];
if(!exsit[edge[u].to]){
exsit[edge[u].to]=true;
inc(tail);dl[tail]=edge[u].to;
}
}
}
}
}
int Spfa(){
memset(dis,63,sizeof dis);
head=0,tail=1;dis[1]=0;dl[1]=1;
while(head!=tail){
inc(head);int v=dl[head];exsit[v]=false;
for(int u=f[v];u;u=e[u].next){
if(e[u].len+dis[v]<dis[e[u].to]){
dis[e[u].to]=e[u].len+dis[v];
if(!exsit[e[u].to]){
exsit[e[u].to]=true;
inc(tail);dl[tail]=e[u].to;
}
}
}
}
return dis[n+1];
}
int main(){
freopen("xxx.in","r",stdin);
freopen("xxx.out","w",stdout);
splay(n),splay(m);
for(int i=1;i<=m;i++){
int s,e,l,r;
splay(s),splay(e),splay(l),splay(r);
if(s==e&&s==1){
ans=min(ans,l),ans=min(ans,r);
}
else addedge(s,e,l),addedge(e,s,r);
}
memset(dis,63,sizeof dis);
for(int u=first[1];u;u=edge[u].next){
dl[++tail]=edge[u].to;
exsit[edge[u].to]=true;
pre[edge[u].to]=edge[u].to;
dis[edge[u].to]=edge[u].len;
}
spfa();
for(int i=1;i<=size;i++){
if(edge[i].to==1){
if(edge[i].from==pre[edge[i].from]){
add(edge[i].from,n+1,edge[i].len);
}
else{
ans=min(ans,dis[edge[i].from]+edge[i].len);
}
}
else if(edge[i].from==1){
if(pre[edge[i].to]!=edge[i].to){
add(1,edge[i].to,edge[i].len);
}
}
else{
if(pre[edge[i].from]==pre[edge[i].to]){
add(edge[i].from,edge[i].to,edge[i].len);
}
else{
add(1,edge[i].to,dis[edge[i].from]+edge[i].len);
}
}

}
cout<<Spfa()<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: