bzoj 4398 福慧双修 题解

来源:互联网 发布:90后女保镖走红网络 编辑:程序博客网 时间:2024/04/29 18:38

卡了一晚上啊

首先我们要跑一边整张图的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 1000000000using 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 1000000000using 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;}



0 0
原创粉丝点击