第二届绿色计算机大赛代码挑战预赛(c++第二阶段)

运输成本

题意

  给出一个有向图,如果点与点之间相互可达,那么经过这些路径不计费,求从某点出发,该图的最长路径是多少。

思路

  targan强连通算法缩点,相互可达的看成一个点,重新建图,再用拓扑排序求最长路

  Ps:存储空间有修改,其他都一样,太大本地编译器无法编译。
  洛谷P3387有道一模一样的题,模板,稍微改一下就行。
  两个模板基本没什么变动,前面一直在尝试删边让他不连通,但是发现不对,随后索性缩点,重建图,因为重建图常数会变大,前面一直不敢尝试

if (Belong[x] != Belong[y])
			{
				add_edge(Belong[x] + n, Belong[y] + n, z);
				indegree[Belong[y] + n]++;
			}
			

  这是缩点重建图的关键

#include <bits/stdc++.h>
using namespace std;

struct Edge
{
	int u, v, w;
};

class Solver
{
public:
	int head[3005], next[3005], tov[3005], dis[3005], num;
	int indegree[1005];
	void add_edge(int from, int to, int len)
	{
		next[++num] = head[from];
		tov[num] = to;
		dis[num] = len;
		head[from] = num;
	}

	int ins[1005], idx, Bcnt;
	int dfn[1005], low[1005];
	int Belong[1005];
	stack <int> s;
	void tarjan(int u)
	{
		int v;
		dfn[u] = low[u] = ++idx;//每次dfs,u的次序号增加1
		s.push(u);//将u入栈
		ins[u] = 1;//标记u在栈内
		for (int i = head[u]; i != -1; i = next[i]) //访问从u出发的边
		{
			v = tov[i];
			if (!dfn[v])//如果v没被处理过
			{
				tarjan(v);//dfs(v)
				low[u] = min(low[u], low[v]);//u点能到达的最小次序号是它自己能到达点的最小次序号和连接点v能到达点的最小次序号中较小的
			}
			else if (ins[v])
			{
				low[u] = min(low[u], dfn[v]);//如果v在栈内,u点能到达的最小次序号是它自己能到达点的最小次序号和v的次序号中较小的
			}
		}
		if (dfn[u] == low[u])
		{
			Bcnt++;
			do
			{
				v = s.top();
				s.pop();
				ins[v] = 0;
				Belong[v] = Bcnt;
			} while (u != v);
		}
	}
	int a[1005], cnt;
	void topu(int n)
	{
		queue<int> q;
		cnt = 1;
		for (int i = n + 1; i <= n + Bcnt - 1; i++)
			if (indegree[i] == 0)
				q.push(i);
		int u;
		while (!q.empty())
		{
			u = q.front();
			a[cnt++] = u;		//将上边选出的没有依赖顶点的节点加入到排序结果中
			q.pop();			//删除队顶元素
			for (int i = head[u]; i != -1; i = next[i])
			{
				int v = tov[i];
				indegree[v] --;			    //删去以u为顶点的边
				if (indegree[v] == 0) 			//如果节点i的所有依赖顶点连接边都已经删去
					q.push(v); //即变为无依赖顶点的节点   将其入队
			}
		}
	}
	void init()
	{
		memset(head, -1, sizeof(head));
		memset(next, 0, sizeof(next));
		memset(tov, 0, sizeof(tov));
		memset(dis, 0, sizeof(dis));
		num = 0;
		memset(indegree, 0, sizeof(indegree));
		memset(ins, 0, sizeof(ins));
		idx = 0, Bcnt = 0;
		memset(dfn, 0, sizeof(dfn));
		memset(low, 0, sizeof(low));
		memset(Belong, 0, sizeof(Belong));
		memset(a, 0, sizeof(a));
	}
public:
	int solve(int n, const vector<Edge> &edges)
	{
		/**********  Begin  **********/
		init();
		int m = edges.size();
		for (int i = 0; i<m; i++)
		{
			int x, y, z;
			x = edges[i].u, y = edges[i].v, z = edges[i].w;
			add_edge(x, y, z);
		}

		for (int i = 1; i <= n; i++)
			add_edge(0, i, 1);
		tarjan(0);

		for (int i = 1; i <= n; i++)
			printf("%d ", Belong[i]);
		cout << endl;

		num = 0;
		memset(head, -1, sizeof(head));
		for (int i = 0; i<m; i++)
		{
			Edge t = edges[i];
			int x = t.u, y = t.v, z = t.w;
			if (Belong[x] != Belong[y])
			{
				add_edge(Belong[x] + n, Belong[y] + n, z);
				indegree[Belong[y] + n]++;
			}
		}
		topu(n);

		int max_dis[1005] = { 0 }, Max = 0;
		for (int i = cnt - 1; i >= 1; i--)
		{
			int u = a[i];
			for (int j = head[u]; j != -1; j = next[j])
			{
				int v = tov[j], len = dis[j];
				max_dis[u] = max(max_dis[u], max_dis[v] + len);
			}
			Max = max(Max, max_dis[u]);
		}
		return Max;
		/**********  End  **********/
	}
};
int main()
{
	Solver xx;
	int n, m;
	cin >> n >> m;
	vector<Edge>yy;
	for (int i = 0; i<m; i++)
	{
		int x, y, z;
		cin >> x >> y >> z;
		Edge t;
		t.u = x, t.v = y, t.w = z;
		yy.push_back(t);
	}
	cout << xx.solve(n, yy) << endl;
	return 0;
}

发布了41 篇原创文章 · 获赞 2 · 访问量 1266

猜你喜欢

转载自blog.csdn.net/qq_41418281/article/details/100018194