关闭

poj-3463 Sightseeing

标签: poj最短路
679人阅读 评论(0) 收藏 举报
分类:

题意:
给出一个n点m边的有向图,求s到t的最短路和长度为最短路+1的路的种类数;

n<=1000,m<=10000;


题解:

对于长度仅为最短路+1的路,处理时我们可以放宽一些限制;

只需求最短路和次短路,然后判断一下次短路是否满足情况就好了;

那么,求最短路+次短路的算法就用dij来处理;

令:

dis[x][k]表示x点的最短路次短路长度;

cnt[x][k]表示x点的最短路次短路分别的种类数;

vis[x][k]表示在dij算法中已经固定了的点,不会再次被更新;

k∈{0,1},分别表示最短路和次短路;

然后每次找出所以路中最小的一个,更新所有可到达的点;

分情况讨论累计种类数,就可以得到答案了;


HINT:

1.实际上dij时因为n较小,用heap实现也是可以的,但是代码比较麻烦,所以直接枚举O(n^2)

2.至于用dij而不用spfa是因为dij算法每个结点只会对其它结点进行一次更新;

   spfa可能多次入队多次更新造成计数错误,但是记录一些东西也是可以做的;

3.dij的循环要执行2*n次因为有2*n个vis数组要更新;


代码:


#include<vector>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 1100
using namespace std;
vector<int>to[N], val[N];
int dis[N][2], cnt[N][2];
int vis[N][2];
void init(int n)
{
	for (int i = 1; i <= n; i++)
		to[i].clear(),
		val[i].clear();
	memset(vis, 0, sizeof(vis));
	memset(cnt, 0, sizeof(cnt));
	memset(dis, 0x3f, sizeof(dis));
}
void Dij(int n)
{
	int s, t, i, j, k, x, y;
	bool fl;
	scanf("%d%d", &s, &t);
	dis[s][0] = 0;
	cnt[s][0] = 1;
	for (i = 1; i <= 2 * n; i++)
	{
		k = 0x3f3f3f3f;
		for (j = 1; j <= n; j++)
		{
			if (!vis[j][0] && dis[j][0] < k)
				x = j, fl = 0, k = dis[j][0];
			else if (!vis[j][1] && dis[j][1] < k)
				x = j, fl = 1, k = dis[j][1];
		}
		if (k == 0x3f3f3f3f)
			break;
		vis[x][fl] = 1;
		for (j = 0; j < to[x].size(); j++)
		{
			y = to[x][j];
			if (dis[y][0]>k + val[x][j])
			{
				dis[y][1] = dis[y][0], cnt[y][1] = cnt[y][0];
				dis[y][0] = k + val[x][j], cnt[y][0] = cnt[x][fl];
			}
			else if (dis[y][0] == k + val[x][j])
				cnt[y][0] += cnt[x][fl];
			else if (dis[y][1] > k + val[x][j])
				dis[y][1] = k + val[x][j], cnt[y][1] = cnt[x][fl];
			else if (dis[y][1] == k + val[x][j])
				cnt[y][1] += cnt[x][fl];
		}
	}
	if (dis[t][1] == dis[t][0] + 1)
		cnt[t][0] += cnt[t][1];
	printf("%d\n", cnt[t][0]);
}
int main()
{
	int c, T, n, m, i, j, k, x, y, v;
	scanf("%d", &T);
	for (c = 1; c <= T; c++)
	{
		scanf("%d%d", &n, &m);
		init(n);
		for (i = 1; i <= m; i++)
		{
			scanf("%d%d%d", &x, &y, &v);
			to[x].push_back(y);
			val[x].push_back(v);
		}
		Dij(n);
	}
	return 0;
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:174261次
    • 积分:3916
    • 等级:
    • 排名:第8061名
    • 原创:216篇
    • 转载:0篇
    • 译文:0篇
    • 评论:42条
    电子邮箱

    ww140142@girigiri.love
    Connect
    博客专栏
    文章分类