【BZOJ 1375】 [Baltic2002]Bicriterial routing 双调路径

来源:互联网 发布:网络爱情歌曲 编辑:程序博客网 时间:2024/04/29 10:19

1375: [Baltic2002]Bicriterial routing 双调路径

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 299  Solved: 115
[Submit][Status]

Description

来越多,因此选择最佳路径是很现实的问题。城市的道路是双向的,每条道路有固定的旅行时间以及需要支付的费用。路径由连续的道路组成。总时间是各条道路旅行时间的和,总费用是各条道路所支付费用的总和。同样的出发地和目的地,如果路径A比路径B所需时间少且费用低,那么我们说路径A比路径B好。对于某条路径,如果没有其他路径比它好,那么该路径被称为最优双调路径。这样的路径可能不止一条,或者说根本不存在。 给出城市交通网的描述信息,起始点和终点城市,求最优双条路径的条数。城市不超过100个,边数不超过300,每条边上的费用和时间都不超过100。

Input

第一行给出有多少个点,多少条边,开始点及结束点. 下面的数据用于描述这个地图

Output

有多少条最优双调路径

Sample Input

4 5 1 4
2 1 2 1
3 4 3 1
2 3 1 2
3 1 1 4
2 4 2 4

Sample Output

2

HINT


分层图上的最短路。


f[i][j]表示走到i结点,费用为j的最少时间,直接跑spfa即可。


#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cstdlib>#include <queue>#define inf 0x3f3f3f3f#define maxc (n-1)*100using namespace std;struct edge{int y,ne,c,t;}e[1000];struct now{int p,c;};int tot=0,n,m;struct data{int t,f;}d[105][10005];int s,t,h[105],inq[105][10005];void Addedge(int x,int y,int co,int ti){tot++;e[tot].y=y;e[tot].ne=h[x];h[x]=tot;e[tot].c=co;e[tot].t=ti;}void spfa(){for (int i=1;i<=n;i++)for (int j=0;j<=maxc;j++)d[i][j].f=0,inq[i][j]=0,d[i][j].t=inf;queue<now> q;now x;x.p=s,x.c=0;d[s][0].f=1,d[s][0].t=0;inq[s][0]=1;q.push(x);while (!q.empty()){x=q.front();q.pop();inq[x.p][x.c]=0;                for (int i=h[x.p];i;i=e[i].ne){int y=e[i].y;int co=e[i].c+x.c;if (co>maxc) continue;if (d[y][co].t>d[x.p][x.c].t+e[i].t){d[y][co].t=d[x.p][x.c].t+e[i].t;d[y][co].f=1;if (!inq[y][co]){now aa;aa.p=y,aa.c=co;q.push(aa),inq[y][co]=1;}}}}}int main(){        scanf("%d%d%d%d",&n,&m,&s,&t);for (int i=1;i<=m;i++){int x,y,ti,co;scanf("%d%d%d%d",&x,&y,&co,&ti);Addedge(x,y,co,ti);Addedge(y,x,co,ti);}spfa();int ans=0,minn=maxc+10;        for (int i=0;i<=maxc;i++){if (!d[t][i].f) continue;if (d[t][i].t>=minn) continue;minn=d[t][i].t;ans++;}cout<<ans<<endl;return 0;}


wa是因为求答案时写了break,应该是continue。


其实这个题还可以进行优化:

如果存在f[i][k],满足k<j且f[i][k]<f[i][j],那么f[i][j]一定不是最优解。


因此我们可以给每一个结点建一棵线段树,维护最小值即可。


#include <iostream>#include <algorithm>#include <cstring>#include <cstdio>#include <cstdlib>#include <queue>#define inf 0x3f3f3f3f#define maxc (n-1)*100+5using namespace std;struct edge{int y,ne,c,t;}e[1000];struct now{int p,c;};int tot=0,n,m;struct data{int t,f;}d[105][10005];int s,t,h[105],inq[105][10005];struct segtree{int l,r,minn;}T[105][40005];void Addedge(int x,int y,int co,int ti){tot++;e[tot].y=y;e[tot].ne=h[x];h[x]=tot;e[tot].c=co;e[tot].t=ti;}void Build(int now,int x,int l,int r){T[now][x].l=l,T[now][x].r=r;if (l==r) {T[now][x].minn=maxc;return;}int m=(l+r)>>1;Build(now,x<<1,l,m);Build(now,(x<<1)+1,m+1,r);T[now][x].minn=maxc;}void Update(int now,int x,int p,int k){if (T[now][x].l==T[now][x].r&&T[now][x].l==p){T[now][x].minn=min(k,T[now][x].minn);return;}int m=(T[now][x].l+T[now][x].r)>>1;if (p<=m) Update(now,x<<1,p,k);else Update(now,(x<<1)+1,p,k);T[now][x].minn=min(T[now][x<<1].minn,T[now][(x<<1)+1].minn);}int Get(int now,int x,int l,int r){if (T[now][x].l>=l&&T[now][x].r<=r)return T[now][x].minn;int m=(T[now][x].l+T[now][x].r)>>1;if (r<=m) return Get(now,x<<1,l,r);if (l>m+1) return Get(now,(x<<1)+1,l,r);return min(Get(now,x<<1,l,r),Get(now,(x<<1)+1,l,r));}void spfa(){for (int i=1;i<=n;i++)for (int j=0;j<=maxc;j++)d[i][j].f=0,inq[i][j]=0,d[i][j].t=inf;queue<now> q;now x;x.p=s,x.c=0;d[s][0].f=1,d[s][0].t=0;inq[s][0]=1;Update(s,1,0,0);q.push(x);while (!q.empty()){x=q.front();q.pop();inq[x.p][x.c]=0;        for (int i=h[x.p];i;i=e[i].ne){int y=e[i].y;int co=e[i].c+x.c;if (co>maxc) continue;if (d[y][co].t>d[x.p][x.c].t+e[i].t&&Get(y,1,0,co)>d[x.p][x.c].t+e[i].t){d[y][co].t=d[x.p][x.c].t+e[i].t;d[y][co].f=1;Update(y,1,co,d[y][co].t);if (!inq[y][co]){now aa;aa.p=y,aa.c=co;q.push(aa),inq[y][co]=1;}}}}}int main(){        scanf("%d%d%d%d",&n,&m,&s,&t);for (int i=1;i<=m;i++){int x,y,ti,co;scanf("%d%d%d%d",&x,&y,&co,&ti);Addedge(x,y,co,ti);Addedge(y,x,co,ti);}for (int i=1;i<=n;i++)Build(i,1,0,maxc);spfa();int ans=0,minn=maxc+10;        for (int i=0;i<=maxc;i++){if (!d[t][i].f) continue;if (d[t][i].t>=minn) continue;minn=d[t][i].t;ans++;}cout<<ans<<endl;return 0;}



进入第一版~


其实没必要用线段树,因为是求前缀的最小值,直接树状数组就可以了。。

1 0
原创粉丝点击