P4995 跳跳!

一开始写的最大生成树,但是没有注意到题目要求每一个石头只能跳一次,如果生成树长下面这样就不对了(从0开始跳,这个不可能是一次跳完的路径)

所以说,只能用贪心,贪心有几种方式,一种是升序排序,然后再高低来回跳就行了,另一种是建无向图跑最长路,最开始是直接dfs+贪心过了,然后用了dijkstra求最长路(dijkstra求不了最长路,但是此处保证确定好最长路的结点不会再被更新后也没问题,其实和dfs+贪心没区别),后来又用路径全部取为相反数然后用dijkstra(这个和之前的求最长路做法没区别,都要标记集合内的点不能再被更新)和spfa分别做了最短路(我傻了...因为建的图一定有环,但是spfa没法求带负环的最短路,直接会超时)

注意点:

  1. dijkstra没法求非负边权最长路,没法用在含负权边的图上
  2. 带正环没法求最长路(其中spfa直接T)
  3. 带负环没法求最短路
  4. bellman-ford/spfa可以用来判断负环
  5. bellman-ford可以用来求从源点到别的点不超过k条边的最短路
#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

const int N = 310;

#define int long long
#define PII pair<int, int>

int n;
int h[N];
int st[N];

vector<vector<PII>> g(N);

int dfs(int u){
    st[u] = 1;
    for(int i = g[u].size() - 1; i >= 0; i --){
        if(st[g[u][i].second]) continue;
        return g[u][i].first + dfs(g[u][i].second);
    }
    return 0;
}

signed main(){
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> h[i];
    
    for(int i = 0; i <= n; i ++){
        for(int j = 0; j <= n; j ++)
            g[i].push_back({(h[i] - h[j]) * (h[i] - h[j]), j});
        sort(g[i].begin(), g[i].end());
    }

    cout << dfs(0) << endl;
    
    return 0;
}
原文地址:https://www.cnblogs.com/tomori/p/15315116.html