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

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;
}

进入第一版~

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

时间: 2024-08-04 13:00:11

【BZOJ 1375】 [Baltic2002]Bicriterial routing 双调路径的相关文章

Bicriterial routing 双调路径 HYSBZ - 1375(分层最短路)

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

BZOJ 2150 部落战争(最小路径覆盖)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2150 题意:一个n*m的国家,有些是障碍.对于一支军队,每次只能走C*R的格式(比如马是走1*2的格式),而且只能从上往下走.每个格子只能被一个军队经过.问最少需要多少军队可以遍历完所有格子? 思路:上下能连边的连边.最后就是最小路径覆盖. int a[N][N],n,m; char s[55][55]; int ID(int i,int j) { return (i-1)*m+j;

BOI 2002 双调路径

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

【BZOJ】2337: [HNOI2011]XOR和路径

[算法]期望+高斯消元 [题解]因为异或不能和期望同时运算,所以必须转为加乘 考虑拆位,那么对于边权为1取反,边权为0不变. E(x)表示从x出发到n的路径xor期望. 对于点x,有E(x)=Σ(1-E(y))(边权1)||E(y)(边权0)/t[x]  t[x]为x的度. 那么有n个方程,整体乘上t[x]确保精度,右项E(x)移到左边--方程可以各种变形. 每次计算完后*(1<<k)就是贡献. 逆推的原因在于n不能重复经过,而1能重复经过,所以如果计算"来源"不能计算n,

bzoj 2044 三维导弹拦截 —— 最小路径覆盖

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2044 第一问暴力 n^2 即可: 注意这道题对位置没要求!所以先按第一维排序一下即可: 然后拆入点和出点,求一个最小路径覆盖即可. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int const

双调路径

https://loj.ac/problem/10083 题目描述 给出一张图,每条边有两个边权,定义其最小路径为不存在一条路径两种边权都小于它的两种边权,求这张图的最小路径的条数. 思路 首先这道题有两类边权,我们考虑把一类边权压入dis数组中,即我们用dis[i][j]表示到达i点,花费费用为j时所需要的最少时间.那么假设我们用w1表示i到j的费用,w2表示i到j的时间,那么dis[i][j]=dis[i][j-w1]+w2.这样我们可以直接进行最短路计算,这样已经足以通过这道题. 不过我们

8.2/baltic神(水)题

bzoj1334: Description N个政党要组成一个联合内阁,每个党都有自己的席位数. 现在希望你找出一种方案,你选中的党的席位数要大于总数的一半,并且联合内阁的席位数越多越好. 对于一个联合内阁,如果某个政党退出后,其它党的席位仍大于总数的一半,则这个政党被称为是多余的,这是不允许的. Input 第一行给出有多少个政党.其值小于等于300 下面给出每个政党的席位数.总席位数小于等于 100000 Output 你的组阁方案中最多能占多少个席位. 背包dp.一开始想着贪心贪心...后

[关于最短路的一些小结]

以前感觉Dijkstra没jb用 今天做了几道题感觉到了一点用处 首先他是在处理密集的图的时候比Spfa会快一点 时间是O(Nlogn)好像 然后有一道题Spfa跑了一分钟Dijkstra 0.1s 忘了什么题 所以Dijksta还是有点用的 其实在这里只想讲一点Dijkstra小的优化而已 并没有打算讲太多东西 1.用堆优化 sb都会写不会看白书(巫泽俊写的) P102-P103 2.其实这个优化不知道Spfa可不可以用 好像也可以,像往常一样 先给道例题 bzoj2200 这道题有单向边 有

Neutron 理解 (3): Open vSwitch + GRE/VxLAN 组网 [Netruon Open vSwitch + GRE/VxLAN Virutal Network]

学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GRE/VxLAN 虚拟网络 (4)Neutron L3 agent (5)TBD 目前,OpenStack Neutron 支持使用两种隧道网络技术 通用路由封装(GRE) 和 VxLAN 来实现虚拟的二层网络.这两种技术大致看起来非常相似,都是需要使用 OpenStack 在计算和网络节点上建立隧道