先做出最小生成树,然后对每个点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;
}