您的位置:首页 > 其它

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

2015-02-16 11:29 183 查看

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)*100
using 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+5
using 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;
}






进入第一版~

其实没必要用线段树,因为是求前缀的最小值,直接树状数组就可以了。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: