题目链接:点击打开链接
题解思路:这图咋一看就是图论,假设我引爆i点能使j点也引爆,那么就将i,j建立有向边。通过建立的图我们还要将强联通分量缩点,说明这个分量的任意一点引爆都能使其他点都引爆,这里缩点需要得到分量中花费最小的那个点,然后就是求缩完点的所有入度为0的点的和就是了。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e3+10;
int n,cost[mx],tot,head[mx],c[mx],rad[mx];
struct node{
int fir;
int sec;
node(){}
node(int fi,int se):fir(fi),sec(se){}
}s[mx],Edge[mx*mx];
void AddEdge(int x,int y)
{
Edge[tot] = node(y,head[x]);
head[x] = tot++;
}
double distance(int x,int y)
{
return sqrt(pow(1.0*s[x].fir-s[y].fir,2)+pow(1.0*s[x].sec-s[y].sec,2));
}
int dfn[mx],id[mx],size,is,sta[mx],ty,type[mx];
bool vis[mx];
void tarjan(int x)
{
dfn[x] = id[x] = ++is;
sta[++size] = x;
vis[x] = 1;
for(int i=head[x];~i;i=Edge[i].sec){
int son = Edge[i].fir;
if(!dfn[son]){
tarjan(son);
id[x] = min(id[x],id[son]);
}else if(vis[son])
id[x] = min(id[x],dfn[son]);
}
if(id[x]==dfn[x]){
ty++;
c[ty] = cost[x];
while(sta[size]!=x){
type[sta[size]] = ty;
vis[sta[size]] = 0;
c[ty] = min(c[ty],cost[sta[size]]);
size--;
}
type[x] = ty,vis[x] = 0,size--;
}
}
int in[mx];
void dfs(int x)
{
vis[x] = 1;
for(int i=head[x];~i;i=Edge[i].sec){
int son = Edge[i].fir;
if(type[x]!=type[son]) in[type[son]]++;
if(vis[son]) continue;
dfs(son);
}
}
int main()
{
int t,cas = 1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(in,0,sizeof(in));
memset(vis,0,sizeof(vis));
ty = size = is = tot = 0;
for(int i=1;i<=n;i++) scanf("%d%d%lld%d",&s[i].fir,&s[i].sec,rad+i,cost+i);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
if(rad[i]>=distance(i,j)) AddEdge(i,j);
}
}
for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
int ans = 0;
for(int i=1;i<=n;i++)
if(!vis[i]) dfs(i);
for(int i=1;i<=ty;i++)
if(!in[i]) ans += c[i];
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}
Kosaraju算法:
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mx = 1e3+10;
int n,cost[mx],tot,head[mx],c[mx],rad[mx];
vector <int> sa,vec[mx];
struct node{
int fir;
int sec;
node(){}
node(int fi,int se):fir(fi),sec(se){}
}s[mx],Edge[mx*mx];
void AddEdge(int x,int y)
{
Edge[tot] = node(y,head[x]);
head[x] = tot++;
}
double distance(int x,int y)
{
return pow(1.0*s[x].fir-s[y].fir,2)+pow(1.0*s[x].sec-s[y].sec,2);
}
int ty,type[mx],in[mx];
bool vis[mx];
void dfs1(int x)
{
if(vis[x]) return ;
vis[x] = 1;
for(int i=head[x];~i;i=Edge[i].sec) dfs1(Edge[i].fir);
sa.push_back(x);
}
void Dfs(int x)
{
if(type[x]) return ;
type[x] = ty;
c[ty] = min(c[ty],cost[x]);
for(int v : vec[x]) Dfs(v);
}
void dfs(int x)
{
vis[x] = 1;
for(int i=head[x];~i;i=Edge[i].sec){
int son = Edge[i].fir;
if(type[x]!=type[son]) in[type[son]]++;
if(vis[son]) continue;
dfs(son);
}
}
int main()
{
int t,cas = 1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
memset(c,inf,sizeof(c));
memset(type,0,sizeof(type));
memset(vis,0,sizeof(vis));
sa.clear();
ty = tot = 0;
for(int i=1;i<=n;i++) scanf("%d%d%d%d",&s[i].fir,&s[i].sec,rad+i,cost+i),vec[i].clear();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
if(1ll*rad[i]*rad[i]>=distance(i,j)) AddEdge(i,j),vec[j].push_back(i);
}
}
for(int i=1;i<=n;i++) if(!vis[i]) dfs1(i);
for(int i=n-1;i>=0;i--) if(!type[sa[i]])
ty++,Dfs(sa[i]);
int ans = 0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
if(!vis[i]) dfs(i);
for(int i=1;i<=ty;i++)
if(!in[i]) ans += c[i];
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}