【HDU5636 BestCoder Round 74 (div1)A】【floyd 最短路 复杂度考核】Shortest Path 一条链3条边1e6个询问的两点最短路

Shortest Path

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1073    Accepted Submission(s): 340


Problem Description
There is a path graph   G=(V,E)  with   n  vertices. Vertices are numbered from   1  to   n  and there is an edge with unit length between   i  and   i+1   (1i<n) . To make the graph more interesting, someone adds three more edges to the graph. The length of each new edge is   1 .

You are given the graph and several queries about the shortest path between some pairs of vertices.
 

Input
There are multiple test cases. The first line of input contains an integer   T , indicating the number of test cases. For each test case:

The first line contains two integer   n  and   m   (1n,m105)  -- the number of vertices and the number of queries. The next line contains 6 integers   a1,b1,a2,b2,a3,b3   (1a1,a2,a3,b1,b2,b3n) , separated by a space, denoting the new added three edges are   (a1,b1) ,   (a2,b2) ,   (a3,b3) .

In the next   m  lines, each contains two integers   si  and   ti   (1si,tin) , denoting a query.

The sum of values of   m  in all test cases doesn't exceed   106 .
 

Output
For each test cases, output an integer   S=(i=1mizi) mod (109+7) , where   zi  is the answer for   i -th query.
 

Sample Input
   
   
   
   
1 10 2 2 4 5 7 8 10 1 5 3 1
 

Sample Output
   
   
   
   
7
 

Source
BestCoder Round #74 (div.2)
 

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 6, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int casenum, casei;
int n, m;
int a[6];
int s, t;
int D(int x, int y) { return abs(x - y); }
//第一种写法,暴力3循环枚举边的经过顺序
int stupid()
{
	int ans = D(s, t);
	for (int i = 0; i < 6; ++i)
	{
		gmin(ans, D(s, a[i]) + 1 + D(a[i ^ 1], t));
		for (int j = 0; j < 6; ++j)if (j != i&&j != (i ^ 1))
		{
			gmin(ans, D(s, a[i]) + 1
				+ D(a[i ^ 1], a[j]) + 1
				+ D(a[j ^ 1], t));
			for (int k = 0; k < 6; ++k)if (k != i&&k != (i ^ 1) && k != j&&k != (j ^ 1))
			{
				gmin(ans, D(s, a[i]) + 1
					+ D(a[i ^ 1], a[j]) + 1
					+ D(a[j ^ 1], a[k]) + 1
					+ D(a[k ^ 1], t));
			}
		}
	}
	return ans;
}
//第二种写法,dfs枚举遍历边的顺序
int ans;
void  dfs(int x, int dis){}
int f[6][6];
void floyd()
{
	for (int i = 0; i < 6; ++i)
	{
		for (int j = 0; j < 6; ++j)
		{
			f[i][j] = abs(a[i] - a[j]);
		}
	}
	for (int i = 0; i < 6; i+=2)f[i][i ^ 1] = f[i ^ 1][i] = 1;
	for (int k = 0; k < 6; ++k)
	{
		for (int i = 0; i < 6; ++i)
		{
			for (int j = 0; j < 6; ++j)
			{
				gmin(f[i][j], f[i][k] + f[k][j]);
			}
		}
	}
}
//第三种写法,floyd
int main()
{
	scanf("%d", &casenum);
	for (casei = 1; casei <= casenum; ++casei)
	{
		scanf("%d%d", &n, &m);
		for (int i = 0; i < 6; ++i)scanf("%d", &a[i]);
		floyd();
		int ans = 0;
		for (LL i = 1; i <= m; ++i)
		{
			scanf("%d%d", &s, &t);
			int tmp = abs(s - t);
			for (int j = 0; j < 6; ++j)
			{
				for (int k = 0; k < 6; ++k)if(k!=j)
				{
					gmin(tmp, abs(a[j] - s) + f[j][k] + abs(t - a[k]));
				}
			}
			ans = (ans + tmp*i) % Z;
		}
		printf("%d\n", ans);
	}
	return 0;
}
/*
【trick&&吐槽】
1,一定要看时间,一定要准确算出复杂度。
不要以为看起来复杂度很小的算法就没问题了,也许能够AC的代码的要求要更小

2,即时我们使得s<t,走边的方向的也不一定全都是是从编号小的走向编号大的。
	也有可能我们需要走到一个编号很小的点,才有方法通向编号大的点,所以我们还是不要讨论,用暴力做的好。

【题意】
T组数据
有n(1e5)个点,它们形成一条链,i号点与i+1号点的距离为1。
然而我们额外多了3条长度为1的边——
(a[0],a[1]),(a[1],a[2]),(a[2],a[3])
有m(1e5)组询问(x,y),让你求出从x到y的最短路
数据保证所有组询问数之和不超1e6

【类型】
最短路 floyd

【分析】
这题比赛时,我想——
每条边显然最多只经过1次,于是我们暴力枚举经过所有边的顺序。
于是单次处理询问的复杂度就变成了6*6*6+6*6+6+1

然而,这样子是会TLE的(BC上TLE,OJ上AC)。
于是,我们要想办法优化。
首先,我们发现,每条边显然只经过一次。
于是枚举量其实只要3!*2^3即可,即6*8=48,而不是我的216.
所以这里走dfs比走我的暴力枚举更快

更进一步,我们发现,一共有6个关键点,我们可以直接跑出这6个关键点到x的最短路。
如果我们经过一个关键点的话,其实必然要经过2个有意义的关键点。于是我们foriforj
然后最后直接用这6个(实际不用算t,只有7个)关键点的30种情况更新答案即可。

【时间复杂度&&优化】
O(216*m)->O(48*m)->O(30*m)

*/

你可能感兴趣的:(题库-HDU,图论-最短路,复杂度计算)