HDU 5934 强连通+缩点 详解

本文深入探讨了深度优先搜索(DFS)及其在图论中的应用,详细讲解了如何通过DFS进行连通块的划分,计算每个连通块内的最小成本,并分析了节点间的依赖关系,最终解决了一个复杂的图论问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include<bits/stdc++.h>
typedef long long int LL;
using namespace std;

const int N   = 2333+7;
const int INF = (~(1<<31))>>1;
int x[N],y[N],r[N],c[N];

int dfn[N],low[N],color[N];
int vis[N],cnt,tot;//(1为在栈中,2为已访问,且不在栈中,0为不在,没访问过)
int cost[N],deg[N];
int mystack[N],len;
vector<int>G[N];

void dfs(int u){
    dfn[u]=low[u]=++cnt;//时间点
    vis[u]=1;//标记
    mystack[++len]=u;//入栈
    int gz=G[u].size();
    for(int i=0,to;i<gz;i++){
        to=G[u][i];
        if(vis[to]==0)dfs(to);//没访问过
        if(vis[to]==1)low[u]=min(low[u],low[to]);//与子树更新最小值
    }
    if(dfn[u]==low[u]){//联通块
        ++tot;int j;
        do{

            j=mystack[len--]; 
            cost[tot]=min(cost[tot],c[j]);//最小花费
            color[j]=tot;//联通块的编号 缩点
            vis[j]=2;//标记 已访问
        }while(j!=u);//回溯
    }
}

LL dis(LL x){return x*x;}

bool judge(int i,int j){//i与j之间的据离与i的半径比较
    return dis(x[i]-x[j])+dis(y[i]-y[j])<=dis(r[i]);
}

int n;
int main(){
    int _,kcase=0;scanf("%d",&_);
    while(_--){
        tot=cnt=len=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d%d%d",&x[i],&y[i],&r[i],&c[i]);

        for(int i=1;i<=n;i++){cost[i]=INF,deg[i]=vis[i]=0;
            for(int j=1;j<=n;j++){
                if(i==j) continue;//构图
                if(judge(i,j))G[i].push_back(j);
            }
        }
        for(int i=1;i<=n;i++) if(vis[i]==0) dfs(i);

        for(int i=1;i<=n;i++){//染色
            int gz=G[i].size();
            for(int j=0,to;j<gz;j++){
                to=G[i][j];
                if(color[i]!=color[to])//编号不相等 不在同一个环
                    deg[color[to]]++;//i-->to to顶点入度++
            }
        }
        int ans=0;
        for(int i=1;i<=tot;i++)//联通快 
            {if(deg[i]==0) ans+=cost[i];//入度为零 需引爆
        printf("Case #%d: %d\n",++kcase,ans);
        for(int i=1;i<=n;i++) G[i].clear();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值