P1807 最长路

链接:https://www.luogu.com.cn/problem/P1807
其实没什么难的,注意点:拓扑排序,把非1的入度为0的点及其衍生点全删了,不然会到一半无法拓扑下去。
关键在于我之前那个删点的操作,先看错误代码:

...
void clearpoint(ll ix)
{
	for (ll i = 0; i < G[ix].size(); i++)
	{
		rd[G[ix][i]]--;
		if (!rd[G[ix][i]])
			clearpoint(G[ix][i]);
	}
}
...
int main()
{
...
for (int i = 2; i <= n; i++)
		if (!rd[i])
			clearpoint(i);
...
}

这里节选的代码很明显是用深度搜索遍历删点,但是会产生问题,会多删点,比如先删了2的子节点3,顺带删除了3的子节点4,然后后面又会遍历到3节点,再删一遍4,导致本来4可以循环结果被删的无法行动,所以只能用队列来删点。
代码:

#include<iostream>
#include<vector>
#include<algorithm>
#include<math.h>
#include<sstream>
#include<string>
#include<string.h>
#include<iomanip>
#include<stdlib.h>
#include<map>
#include<queue>
#include<limits.h>
#include<climits>
#include<fstream>
#include<stack>
typedef long long ll;
using namespace std;
const int N = 1e3 + 500 + 10;
ll minn[N]; bool vis[N];
ll vw[N][N];
vector<ll>G[N]; ll rd[N];
int main()
{
	ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
	ll n, m; cin >> n >> m;
	for (int i = 0; i < N; i++)minn[i] = LLONG_MIN;
	for (int i = 0; i < m; i++)
	{
		ll u, v, w; cin >> u >> v >> w;
		if (!vw[u][v])
		{
			G[u].push_back(v);
			rd[v]++;
			vw[u][v] = w;
		}
		else vw[u][v] = max(vw[u][v], w);
	}
	queue<ll>qid;
	minn[1] = 0;
	qid.push(1);
//////////正确删点操作////////////
	queue<ll>q;
	for (int i = 2; i <= n; i++)
	{
		if (!rd[i]) q.push(i);
	}//初始化
	while (!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = 0; i < G[x].size(); i++)
			if (!--rd[G[x][i]]) q.push(G[x][i]);
	}
//////////正确删点操作////////////
	while (!qid.empty())
	{
		ll now = qid.front(); qid.pop();
		for (ll i = 0; i < G[now].size(); i++)
		{
			ll wnow = vw[now][G[now][i]], nexid = G[now][i];
			vis[nexid] = 1;
			rd[nexid]--;
			minn[nexid] = max(minn[nexid], wnow + minn[now]);
			if (!rd[nexid])qid.push(nexid);
		}
	}
	if (vis[n])cout << minn[n];
	else cout << -1;
	return 0;
}

posted on 2024-05-15 22:23  WHUStar  阅读(2)  评论(0编辑  收藏  举报