HDU 5636:Shortest Path floyd

Shortest Path

 
 Accepts: 80
 
 Submissions: 431
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
问题描述
有一条长度为nn的链. 节点iii+1i+1之间有长度为11的边. 现在又新加了3条边, 每条边长度都是1. 给出mm个询问, 每次询问两点之间的最短路.
输入描述
输入包含多组数据. 第一行有一个整数TT, 表示测试数据的组数. 对于每组数据:

第一行包含2个整数nnmm (1 \le n,m \le 10^5)(1n,m105)表示节点的数目和询问数目. 接下来一行包含66个有空格分开的整数a_1, b_1, a_2, b_2, a_3, b_3a1,b1,a2,b2,a3,b3 (1 \le a_1,a_2,a_3,b_1,b_2,b_3 \le n)(1a1,a2,a3,b1,b2,b3n), 表示新加的三条边为(a_1,b_1)(a1,b1), (a_2,b_2)(a2,b2), (a_3,b_3)(a3,b3). 接下来mm行, 每行包含两个整数s_isit_iti (1 \le s_i, t_i \le n)(1si,tin), 表示一组询问.

所有数据中mm的和不超过10^6106.
输出描述
对于每组数据, 输出一个整数S=(\displaystyle\sum_{i=1}^{m} i \cdot z_i) \text{ mod } (10^9 + 7)S=(i=1mizi) mod (109+7), 其中z_izi表示第ii组询问的答案.
输入样例
1
10 2
2 4 5 7 8 10
1 5
3 1
输出样例
7

添加三条边,然后再“硬算”,要考虑很多种情况。

对添加的6个点floyd算出最短距离,然后对每对u,v,枚举中间的两个点。

代码:

#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

#define INF 0x3fffffffffffffff

const ll mod = 1e9 + 7;
const int maxn = 1e5 + 5;

int n, m;
int a[10], b[10];
int dis[10][10];

int getpos(int x)
{
	return lower_bound(a + 1, a + 6 + 1, x) - a;
}
void solve()
{
	int i, j, k;
	int x1, x2, u, v;

	scanf("%d%d", &n, &m);

	for (i = 1; i <= 6; i++)
	{
		scanf("%d", &a[i]);
		b[i] = a[i];
	}
	sort(a + 1, a + 6 + 1);
	for (i = 1; i <= 6; i++)
	{
		for (j = 1; j <= 6; j++)
		{
			dis[i][j] = abs(a[i] - a[j]);
		}
	}
	x1 = getpos(b[1]);
	x2 = getpos(b[2]);

	dis[x1][x2] = dis[x2][x1] = min(dis[x1][x2], 1);

	x1 = getpos(b[3]);
	x2 = getpos(b[4]);

	dis[x1][x2] = dis[x2][x1] = min(dis[x1][x2], 1);

	x1 = getpos(b[5]);
	x2 = getpos(b[6]);

	dis[x1][x2] = dis[x2][x1] = min(dis[x1][x2], 1);

	//做的时候没有注意到这里。。。
	for (k = 1; k <= 6; k++)
	{
		for (i = 1; i <= 6; i++)
		{
			for (j = 1; j <= 6; j++)
			{
				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
			}
		}
	}
	ll ans = 0;
	for (k = 1; k <= m; k++)
	{
		scanf("%d%d", &u, &v);
		ll res = abs(u - v);

		for (i = 1; i <= 6; i++)
		{
			for (j = 1; j <= 6; j++)
			{
				res = min(res, (ll)(abs(u - a[i]) + abs(v - a[j]) + dis[i][j]));
			}
		}
		ans = (ans + (ll)(res*k)%mod) % mod;
	}
	printf("%lld\n", ans);
}

int main()
{
#ifndef ONLINE_JUDGE  
	freopen("i.txt", "r", stdin);
	freopen("o.txt", "w", stdout);
#endif 

	int t;
	scanf("%d", &t);
	while (t--)
	{
		solve();
	}

	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值