洛谷·bzoj·GPS的决斗Dueling GPS‘s

初见安~这里是传送门:洛谷P3106 & bzoj P3538

题目描述

Farmer John has recently purchased a new car online, but in his haste he accidentally clicked the "Submit" button twice when selecting extra features for the car, and as a result the car ended up equipped with two GPS navigation systems! Even worse, the two systems often make conflicting decisions about the route that FJ should take.

The map of the region in which FJ lives consists of N intersections (2 <= N <= 10,000) and M directional roads (1 <= M <= 50,000). Road i connects intersections A_i (1 <= A_i <= N) and B_i (1 <= B_i <= N). Multiple roads could connect the same pair of intersections, and a bi-directional road (one permitting two-way travel) is represented by two separate directional roads in opposite orientations. FJ's house is located at intersection 1, and his farm is located at intersection N. It is possible to reach the farm from his house by traveling along a series of directional roads.

Both GPS units are using the same underlying map as described above; however, they have different notions for the travel time along each road. Road i takes P_i units of time to traverse according to the first GPS unit, and Q_i units of time to traverse according to the second unit (each travel time is an integer in the range 1..100,000).

FJ wants to travel from his house to the farm. However, each GPS unit complains loudly any time FJ follows a road (say, from intersection X to intersection Y) that the GPS unit believes not to be part of a shortest route from X to the farm (it is even possible that both GPS units can complain, if FJ takes a road that neither unit likes).

Please help FJ determine the minimum possible number of total complaints he can receive if he chooses his route appropriately. If both GPS units complain when FJ follows a road, this counts as +2 towards the total.

给你一个N个点的有向图,可能有重边.

有两个GPS定位系统,分别认为经过边i的时间为Pi,和Qi.

每走一条边的时候,如果一个系统认为走的这条边不是它认为的最短路,就会受到警告一次T T

两个系统是分开警告的,就是说当走的这条边都不在两个系统认为的最短路范围内,就会受到2次警告.

如果边(u,v)不在u到n的最短路径上,这条边就受到一次警告,求从1到n最少受到多少次警告。

输入格式:

* Line 1: The integers N and M.

Line i describes road i with four integers: A_i B_i P_i Q_i.

输出格式:

* Line 1: The minimum total number of complaints FJ can receive if he routes himself from his house to the farm optimally.

输入样例#1: 

5 7 
3 4 7 1 
1 3 2 20 
1 4 17 18 
4 5 25 3 
1 2 10 1 
3 5 4 14 
2 4 6 5 

输出样例#1: 

1

题解:

【本狸写的代码比较冗长,所以建议看思路然后自己码QwQ】

题意很明显——两个GPS,两个图,各有各的最短路,你走的边在哪个图上不属于最短路哪个图就会报错。再简洁些,就是求两个图的最短路最短非公共部分。倒过来,就和Elaxia的路线【传送门】差不多的题意了。只是这个题要简单些,是有向图。

如果一条边在其中一个图里不属于最短路的边,那么就要报错一次。也就是说我们可以处理出每一条边会报错多少次,然后再走一遍最短路找最少报错次数。至此你已经可以自己去码代码了。

对于如何处理处每一条边是否属于最短路,我们可以把两个图存反图,从终点跑一遍每个点到终点的距离,再枚举每条边,如果dis[u] + e[i].w = dis[v],那么这条边就是一条最短路上的边。这里的处理我写的很冗长……前前后后开了4个图QAQ存图方式果然还是很重要的……

思路就这么两步,很简单吧……上我代码——

#include<bits/stdc++.h>
using namespace std;
int read()
{
	int x = 0, ch = getchar();
	while(!isdigit(ch)) ch = getchar();
	while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
	return x;
}

const int maxn = 1e5;
int n, m;
struct edge
{
	int to, w, nxt;
	edge() {}
	edge(int tt, int ww, int nn) {to = tt, w = ww, nxt = nn;}
}e1[100005], e2[100005], e3[100005];//反图两个,报错次数图一个 

int head1[maxn], k1 = 0;
void add_1(int u, int v, int w)
{
	e1[k1] = edge(v, w, head1[u]);
	head1[u] = k1++;
}

int head2[maxn], k2 = 0;
void add_2(int u, int v, int w)
{
	e2[k2] = edge(v, w, head2[u]);
	head2[u] = k2++;
}

int head3[maxn], k3 = 0;
void add_3(int u, int v, int w)
{
	e3[k3] = edge(v, w, head3[u]);
	head3[u] = k3++;
}

int dis1[maxn], dis2[maxn];
int cnt1, cnt2;
bool vis[maxn];
void spfa(int u, int *dis, int *head, edge *e)//指针传送调用数组,开一个最短路就可以了 
{//这里的最短路是模板操作,没有什么特别之处 
	memset(vis, 0, sizeof vis);
	dis[u] = 0;
	queue<int> q;
	q.push(u);
	register int v;
	while(q.size())
	{
		u = q.front(); q.pop(); vis[u] = 0;
		for(int i = head[u]; ~i; i = e[i].nxt)
		{
			v = e[i].to;
			if(dis[u] + e[i].w < dis[v])
			{
				dis[v] = dis[u] + e[i].w;
				if(!vis[v]) q.push(v), vis[v] = 1;
			}
		}
	}
}

int g[maxn][4];

void resign()//判断每条边 
{
	register int u, v, w1, w2;
	for(int i = 1; i <= m; i++)
	{
		u = g[i][0], v = g[i][1], w1 = g[i][2], w2 = g[i][3];
		if(dis1[u] - w1 == dis1[v] && dis2[u] - w2 == dis2[v]) add_3(u, v, 0);//, printf("edge:%d %d %d\n", u, v, 0);
		else if(dis1[u] - w1 != dis1[v] && dis2[u] - w2 != dis2[v]) add_3(u, v, 2);//, printf("edge:%d %d %d\n", u, v, 2);
		else add_3(u, v, 1);//, printf("edge:%d %d %d\n", u, v, 1);
	}
}

int main()
{
//	freopen("in.txt", "r", stdin);
	memset(head1, -1, sizeof head1);
	memset(head2, -1, sizeof head2);
	memset(head3, -1, sizeof head3);
	memset(dis1, 0x3f, sizeof dis1);
	memset(dis2, 0x3f, sizeof dis2);
	n = read(), m = read();
	int u, v, w;
	for(int i = 1; i <= m; i++)
	{
		u = read(), v = read(), w = read(), add_1(v, u, w);
		g[i][2] = w;//g存一个正图,后期判断边的时候用【可能可以不开…… 
		w = read(); add_2(v, u, w);
		g[i][3] = w;
		g[i][0] = u, g[i][1] = v;
	}
	
	spfa(n, dis1, head1, e1);//反图跑最短路 
	spfa(n, dis2, head2, e2);
	
	resign();
	
	memset(dis1, 0x3f, sizeof dis1);
	spfa(1, dis1, head3, e3);
	printf("%d\n", dis1[n]);
	return 0;
}

可以说真的很冗长了QwQ

迎评:)
——End——

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值