先做出最小生成树,然后对每个点dfs判断树边是否可删.....
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 3005; const int maxm = 6005; const int INF = 0x3f3f3f3f; struct Edge { int v; Edge *next; }E[maxm], *H[maxn], *edges; int g[maxn][maxn]; int is[maxn][maxn]; int lowc[maxn]; int pre[maxn]; int dis[maxn]; int vis[maxn]; int n; void init() { edges = E; memset(H, 0, sizeof H); memset(is, 0, sizeof is); } void addedges(int u, int v) { edges->v = v; edges->next = H[u]; H[u] = edges++; } void Prim() { memset(vis, 0, sizeof vis); vis[1] = true; for(int i = 1; i <= n; i++) lowc[i] = g[1][i], pre[i] = 1; for(int i = 1; i < n; i++) { int minc = INF; int p = -1, t = -1; for(int j = 1; j <= n; j++) if(!vis[j] && minc > lowc[j]) { minc = lowc[j]; p = j; t = pre[j]; } vis[p] = true; for(int j = 1; j <= n; j++) if(!vis[j] && lowc[j] > g[p][j]) { lowc[j] = g[p][j]; pre[j] = p; } is[p][t] = is[t][p] = true; } } void dfs(int u, int fa) { for(Edge *e = H[u]; e; e = e->next) if(e->v != fa) { int v = e->v; dfs(e->v, u); dis[u] = min(dis[u], dis[v]); } if(g[fa][u] >= dis[u]) is[fa][u] = is[u][fa] = 0; } void debug() { for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) printf("%d ", is[i][j]); printf("\n"); } } void work() { scanf("%d", &n); for(int i = 1; i < n; i++) for(int j = 1; j <= n - i; j++) { int x; scanf("%d", &x); g[i][i+j] = g[i+j][i] = x; } for(int i = 1; i <= n; i++) g[i][i] = 0; Prim(); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) if(is[i][j]) addedges(i, j); for(int i = 1; i <= n; i++) g[0][i] = INF; for(int i = 1; i <= n; i++) { for(int j = 1; j <= n; j++) { if(is[i][j]) dis[j] = INF; else dis[j] = g[i][j]; } dfs(i, 0); } int ans = 0; for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) ans += is[i][j]; printf("%d\n", ans / 2); } int main() { //freopen("data", "r", stdin); int _; scanf("%d", &_); while(_--) { init(); work(); } return 0; }