zoukankan      html  css  js  c++  java
  • 2016CCPC杭州现场赛 B-Bomb /// tarjan缩点

    题目大意:

    给定n个爆破点的信息 x y r w

    表示爆破点位置为 (x,y) 爆破范围是以位置为圆心 半径为r的圆 引爆这个点的代价为w

    引爆某个点时 其他位置在该爆破范围内的爆破点也会被引爆

    求引爆所有爆破点的最小的爆破代价

    这道题跟 上一篇的 OJ 22833(POJ 2186) 差不多

    那题是缩点再计算出度 这题是缩点再计算入度

    以爆破关系建图 即若引爆 i 点能使 j 点被引爆 那么连一条 i 到 j 的边

    若存在点 k 的位置被包含在点 j 的爆破范围内,点 j 的位置被包含在点 i 的爆破范围内,但点 k 的位置不被包含在点 i 的爆破范围内

    此时若引爆 i 点 那么 j 点会被引爆,而 j 点被引爆 k 点也会被引爆,即爆破存在传递性

    所以求完这个图的强联通分量并缩点后 此时引爆这个图的里一个强联通分量

    那么这个强联通分量能到达的其他强联通分量也会被引爆


    又因为一个强联通分量内任意两点能互达 所以引爆一个强联通分量只需要引爆它内部的其中一个点

    那么引爆一个强联通分量 应该贪心地选择它内部爆破代价最小的那个点

    所以此时需要引爆的就是那些 入度为0的强联通分量内爆破代价最小的点 (由它们开始发生连环引爆)(图内的独立点入度也为0)

    #include <stdio.h>
    #include <cstring>
    #include <algorithm>
    #include <stack>
    #define LL long long
    #define INF 0x3f3f3f3f
    using namespace std;
    
    const int N=1005;
    struct EDGE { int to, nt; }e[N*N];
    int head[N], tot;
    int dfn[N], low[N], ind;
    int col[N], id;
    bool vis[N];
    stack <int> s;
    
    int n, m, du[N];
    LL x[N], y[N], r[N];
    LL w[N], val[N];
    
    void init() {
        while(!s.empty()) s.pop();
        for(int i=0;i<=n;i++) {
            head[i]=dfn[i]=low[i]=col[i]=-1;
            vis[i]=du[i]=0; val[i]=INF;
        }
        tot=ind=id=0;
    }
    void addE(int u,int v) {
        e[tot].to=v;
        e[tot].nt=head[u];
        head[u]=tot++;
    }
    
    void tarjan(int u) {
        dfn[u]=low[u]=ind++;
        s.push(u); vis[u]=1;
        for(int i=head[u];i!=-1;i=e[i].nt) {
            int v=e[i].to;
            if(dfn[v]==-1) {
                tarjan(v);
                low[u]=min(low[u],low[v]);
            }
            else if(vis[v])
                low[u]=min(low[u],low[v]);
        }
        if(dfn[u]==low[u]) {
            col[u]=++id;
            vis[u]=0;
            while(s.top()!=u) {
                col[s.top()]=id;
                vis[s.top()]=0;
                s.pop();
            } s.pop();
        }
    }
    
    bool uni(int i,int j) {
        LL dis=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
        if(dis<=r[i]*r[i]) return 1;
        return 0;
    }
    
    int main()
    {
        int t, tcase=0;
        scanf("%d",&t);
        while(t--) {
            scanf("%d",&n);
            for(int i=1;i<=n;i++)
                scanf("%lld%lld%lld%lld",&x[i],&y[i],&r[i],&w[i]);
            init();
            for(int i=1;i<=n;i++)
                for(int j=i+1;j<=n;j++) {
                    if(uni(i,j)) addE(i,j); // j在i的爆破范围内 连i->j
                    if(uni(j,i)) addE(j,i); // i在j的爆破范围内 连j->i
                }
    
            for(int i=1;i<=n;i++)
                if(dfn[i]==-1) tarjan(i);
    
            for(int i=1;i<=n;i++) {
                val[col[i]]=min(val[col[i]],w[i]); 
                // 颜色相同说明在同个强联通分量内 
                // 保存这个强联通分量内爆破代价最小的点
                for(int j=head[i];j!=-1;j=e[j].nt)
                    if(col[e[j].to]!=col[i])
                        du[col[e[j].to]]++; // 计算各个强联通分量的入度
            }
    
            LL ans=0LL;
            for(int i=1;i<=id;i++)
                if(du[i]==0) ans+=val[i]; // 入度为0 引爆
            printf("Case #%d: %lld
    ",++tcase,ans);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    Ubuntu下的Apache、Mysql、PHP环境搭建
    JS代码引用位置问题-转
    mysql设置定时任务
    js setTimeout函数
    JavaScript向window onload添加加载函数
    写在开博之时
    WPF笔记(一)之初识XMAL
    创建理想的数据库索引
    常见负载均衡算法
    Java设计模式之外观模式
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10011835.html
Copyright © 2011-2022 走看看