1. 程式人生 > >「國慶訓練」Bomb(HDU-5934)

「國慶訓練」Bomb(HDU-5934)

+= edge memset 說了 ring begin 就是 連通 cas

題意

給定\(n\)個炸彈,每個炸彈的坐標與代價與影響範圍給定,炸彈會引爆影響範圍內其他所有炸彈。求引爆所有炸彈的最小代價。

分析

先做\(n^2\)的循環,然後建圖,對\(i\)能引爆\(j\)建邊\((i,j)\)。然後對這個圖求強連通分量並縮點,構成新的有向無環的森林。定義每個強連通分量的cost為其中包含的點的最小cost,然後把新森林中所有入度為0的點的cost加起來求和即可(由於無環,所以從任何入度不為0的點往回走,必然終止於一個入度為0的點)。

代碼

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <stack>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
#define QUICKIO                      ios::sync_with_stdio(false);     cin.tie(0);                      cout.tie(0);
#define MS(x,y) memset(x,y,sizeof(x))
#define int ll
using namespace std;
typedef long long ll;

const int MAXN=1005;
vector<int> G[MAXN];
bool mat[MAXN][MAXN];
int n;
int pre[MAXN], lowlink[MAXN], sccno[MAXN], dfs_clock, scc_cnt;
stack<int> stk;

void dfs(int u)
{
    pre[u]=lowlink[u] = ++dfs_clock;
    stk.push(u);
    rep(i,0,n-1)
    {
        if(!mat[u][i]) continue; 
        int v=i;
        if(!pre[v])
        {
            dfs(v);
            lowlink[u]=min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v])
        {
            lowlink[u]=min(lowlink[u],pre[v]);
        }
    }
    if(lowlink[u]==pre[u])
    {
        scc_cnt++;
        for(;;)
        {
            int x=stk.top(); stk.pop();
            sccno[x]=scc_cnt;
            if(x==u) break;
        }
    }
}

void find_scc()
{
    dfs_clock=scc_cnt=0;
    ZERO(sccno);
    ZERO(pre);
    rep(i,0,n-1)
        if(!pre[i]) dfs(i);
}

bool nmat[MAXN][MAXN];

vector<pair<int,int> > edges;
vector<int> nG[MAXN];
int ncnt=0;

void add_edges(int u,int v)
{
    edges.PB(MP(u,v));
    nG[u].PB(edges.size()-1);
}

pair<int,int> pnt[MAXN];
int pntc[MAXN], pntr[MAXN];

inline double dist(int x,int y)
{
    return sqrt((pnt[x].fi-pnt[y].fi)*(pnt[x].fi-pnt[y].fi)+
                (pnt[x].se-pnt[y].se)*(pnt[x].se-pnt[y].se));
}
int cost[MAXN];
signed main()
{
    int T; scanf("%lld", &T);
    rep(kase,1,T)
    {
        ZERO(nmat);
        ZERO(mat);
        scanf("%lld", &n);
        rep(i,1,n)
        {
            int x,y;
            scanf("%lld%lld%lld%lld", &x,&y, &pntr[i], &pntc[i]);
            pnt[i]=MP(x,y);
        }
        rep(i,1,n)
        {
            rep(j,1,n)
            {
                if(i==j) continue;
                double d=pntr[i]-dist(i,j);
                if(fabs(d)<1e-6 || d>1e-6)
                {
                    mat[i-1][j-1]=true;
                }
            }
        }
        /*
        rep(i,0,n-1)
        {
            rep(j,0,n-1)
                cout<<mat[i][j]<<" ";
            cout<<endl;
        }
        */
        find_scc();
        memset(cost,0x3f,sizeof(cost));
        rep(i,1,n)
        {
            cost[sccno[i-1]]=min(cost[sccno[i-1]],pntc[i]);
        }
        rep(i,0,n-1)
        {
            rep(j,0,n-1)
            {
                if(i==j) continue;
                nmat[sccno[i]][sccno[j]]|=
                    mat[i][j];
            }
        }
        /*
        rep(i,1,scc_cnt)
        {
            rep(j,1,scc_cnt)
                cout<<nmat[i][j]<<" ";
            cout<<endl;
        }
        */
        ll ans=0;
        /*
        rep(i,0,n-1) cout<<sccno[i]<<" ";
        cout<<endl;
        rep(i,0,n-1) cout<<cost[i]<<" ";
        cout<<endl;
        */
        
        rep(i,1,scc_cnt)
        {
            int ok=0;
            rep(j,1,scc_cnt)
            {
                if(i==j) continue;
                if(nmat[j][i])
                {
                    ok++;
                    break;
                }
            }
            if(!ok)
            {
                //cout<<i<<" "<<cost[i]<<endl;
                ans+=cost[i];
            }
        }
        printf("Case #%lld: %lld\n", kase, ans);
    }
    return 0;
}

劄記

這題是在一場訓練賽中打的。當時的我們激情卡題兩個半小時23333然後我覺得不行了只能換題,不懂圖論的隊友說了這題可以寫,他覺得是帶權並查集23333我想了一下,這一看就是縮點啊。然後縮點之後沒什麽好辦法,不過也沒浪費時間——他們還在卡題23333過了又是半個小時,他們終於出了另外一題(卡的那個簽到題還是沒出!!!),這個時候還剩下一個半小時了,我想到可以求和入度為0的點即可。然後又過去半個小時(出簽到題啊啊啊啊啊)沒出(- -|||),只好我上寫這題,然後半個小時寫完,5分鐘調試,交上去WA,看了下代碼,改了個long long,過了。後來那個簽到題成功出了(太真實了),我們翻盤大成功,哇哢哢~

「國慶訓練」Bomb(HDU-5934)