HDU 3873 Invade the Mars

版权声明:本人QQ 249712949 欢迎交流算法(请备注)。 https://blog.csdn.net/coord_/article/details/88979720

传送门

带限制最短路。
一个有向图,给定起点终点,求结点依赖关系下的最短路。所谓结点依赖,是指每个结点i都依赖于零个或多个其他结点,结点i可访问当且仅当它依赖的这些结点都已经访问过。(可以确定的是,起点肯定不依赖于任何点,而且每个点都不可能依赖于自身)

还有,这道题边权的实际意义是时间。这一点和其他最短路的题都不一样!所以d[]数组代表的就是两点之间最短路花费的时间(不仅包括走每条边花的时间,还包括的时间)。

这道题(只能? )用dijkstra完成,dijkstra最短路算法可以保证每次大循环找到的u点不重复(因为有vis[]数组控制着),每个点最多只当一次中介点。然后,某个点成为中介点的必要条件是它依赖的那些点都已经访问过(这里用数组cnt[]记录每个点依赖的那些结点还差几个没访问)。当找到一个合法的中介点以后,要更新所有的依赖这个中介点的那些结点(这里是依赖当前点的点,不是当前点依赖的点)的信息,首先这些点各自的cnt[]可以减一了,然后这些点的d[]如果小于d[u],则置为d[u](因为这些点依赖于中介点u,中介点被访问完才有可能访问这些点,所以这些点的d[]至少d[u])。

上述说的有点绕,其实A依赖B的意思就是B城市里面装有A城市的屏障发生器。根据上述思想,我们需要统计A依赖的点的个数,以及B指向A的这个关系(也就是说通过B能找到A)。


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
using namespace std;

const int INF = 1e9;
const int MAXN = 3001;
int N, M, T;

struct Edge
{
	int n, w;
};
vector<Edge> ve;
vector<int> v[MAXN];

vector<int> to[MAXN];
int cnt[MAXN];

int d[MAXN];
bool vis[MAXN];

void init()
{
	ve.clear();
	memset(cnt, 0, sizeof cnt);
	for (int i = 1; i <= N; i++)
	{
		v[i].clear();
		to[i].clear();
	}
}

void dijkstra(int s)
{
	memset(vis, 0, sizeof vis);
	fill(d + 1, d + N + 1, INF);
	d[s] = 0;
	for (int i = 0; i < N; i++)
	{
		int u = -1, mind = INF;
		for (int j = 1; j <= N; j++)
		{
			if (!cnt[j])                               ////
			{
				if (!vis[j] && d[j] < mind)
				{
					mind = d[j];
					u = j;
				}
			}
		}
		vis[u] = true;
		for (int j = 0; j < to[u].size(); j++)         ////  对dijkstra而言,u只当这么一次中介点
		{
			d[to[u][j]] = max(d[to[u][j]], d[u]);
			cnt[to[u][j]]--;
		}
		for (int j = 0; j < v[u].size(); j++)
		{
			int n = ve[v[u][j]].n;
			int w = ve[v[u][j]].w;
			if (!vis[n] && d[u] + w < d[n])
			{
				d[n] = d[u] + w;
			}
		}
	}
}

int main()
{
	int a, b, c;
	scanf("%d", &T);
	for (; T--;)
	{
		scanf("%d%d", &N, &M);
		init();
		for (int i = 0; i < M; i++)
		{
			scanf("%d%d%d", &a, &b, &c);
			ve.push_back(Edge{ b,c });
			v[a].push_back(i);
		}
		for (int i = 1; i <= N; i++)
		{
			scanf("%d", &a);
			for (; a--;)
			{
				scanf("%d", &b);
				cnt[i]++;                  // 当前城市i被多少个城市保护着
				to[b].push_back(i);        // 城市b保护当前城市i
			}
		}

		dijkstra(1);
		printf("%d\n", d[N]);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/coord_/article/details/88979720