题解:建有向图,trajan缩点求强连通分量,板子题
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define ll long long
#define MAX 10001
int n,m;
//前向星
struct Edge
{
int to,next;
}edge[1005*1005];
int head[MAX*2],tol;
void add(int a,int b)
{
edge[tol].to = b;
edge[tol].next = head[a];
head[a] = tol ++;
}
//tarjan算法
int dfn[MAX*2],low[MAX*2],stack[MAX*2],belong[MAX*2],time,top,cnt;
bool instack[MAX*2];
int in[MAX*2],out[MAX*2];//记录缩点后的入度出度
void tarjan(int u)
{
int v;
dfn[u] = low[u] = ++time;
stack[top ++] = u;
instack[u] = true;
for(int j = head[u] ; j != -1; j = edge[j].next)
{
v = edge[j].to;
if(!dfn[v])
{
tarjan(v);
if(low[v] < low[u])
low[u] = low[v];
}
else if(instack[v] && dfn[v] <low[u])
low[u] = dfn[v];
}
if(dfn[u] == low[u])
{
cnt ++;
do
{
v = stack[-- top];
instack[v] = false;
belong[v] = cnt;
}while(v != u);
}
}
ll x[1005],y[1005],r[1005];
int val[1005];
int main()
{
int a,b;
int T;
scanf("%d",&T);
int Case=0;
while(T --)
{
Case++;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld%lld%d",&x[i],&y[i],&r[i],&val[i]);
}
//建图
tol = 0;
memset(head,-1,sizeof(head));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j)continue;
ll dist=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
if(dist<=r[i]*r[i])
add(i,j);
}
}
//缩点
cnt = time = top = 0;
memset(dfn,0,sizeof(dfn));
for(int i = 1; i <= n; i ++)
if(!dfn[i])
tarjan(i);
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(int i = 1; i <= n; i ++)
{
for(int k = head[i]; k != -1; k = edge[k].next)
{
int j = edge[k].to;
if(belong[i] != belong[j])
out[belong[i]] ++, in[belong[j]] ++;
}
}
//缩点之后找叶子和根的数量ll
int ans=0;
for(int i = 1; i <= cnt; i ++)
{
if(in[i]==0)
{
int mi=1e9;
for(int j=1;j<=n;j++)
{
if(belong[j]==i)
mi=min(mi,val[j]);
}
ans+=mi;
}
}
printf("Case #%d: %d\n",Case,ans);
}
return 0;
}