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;
}