2016 ICPC Mid-Central USA Region Ghostbusters 2

本文探讨了一种基于激光发射策略的问题解决方法,通过构建图模型并运用强连通分量算法,有效地判断了在特定条件下激光发射是否可行。文章详细介绍了算法流程,包括二分查找、图的构建、以及Tarjan算法的应用。

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

链接

https://nanti.jisuanke.com/t/40895

题解

首先二分
然后问题就是怎么 c h e c k check check
建图,对每个 ( x i , y i ) (x_i,y_i) (xi,yi)建两个点,一个点表示它横着发射激光,一个点表示它竖着发射激光
如果点 ( x i , y i ) (x_i,y_i) (xi,yi)横着就会导致 ( x j , y j ) (x_j,y_j) (xj,yj)必须竖着,那就从横 i _i i到竖 j _j j连一条边
最后看下对于每个 i i i,横 i _i i和竖 i _i i如果在同一个强连通分量里,那就不行,否则就可以

代码

#include <bits/stdc++.h>
#define maxn 40010
#define maxe 10000010
#define linf (1ll<<60)
#define iinf 0x3f3f3f3f
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
int N, x[maxn], y[maxn];
struct Graph
{
    int etot, head[maxn], to[maxe], next[maxe];
    void clear(int N)
    {
        for(int i=1;i<=N;i++)head[i]=0;
        etot=0;
    }
    void adde(int a, int b, int c=0){to[++etot]=b;next[etot]=head[a];head[a]=etot;}
}G;
struct Trajan_SCC
{
    int dfn[maxn], low[maxn], vis[maxn], scc[maxn], tim, scc_cnt;
    stack<int> s;
    void clear(int n)
    {
        for(int i=1;i<=n;i++)vis[i]=0;
        tim=scc_cnt=0;
    }
    void dfs(Graph &G, int pos)
    {
        int p;
        dfn[pos]=low[pos]=++tim;
        s.emplace(pos);
        vis[pos]=1;
        for(p=G.head[pos];p;p=G.next[p])
        {
            if(vis[G.to[p]]==0)dfs(G,G.to[p]);
            if(vis[G.to[p]]==1)low[pos]=min(low[pos],low[G.to[p]]);
        }
        if(dfn[pos]==low[pos])
        {
            int x;
            scc_cnt++;
            do
            {
                x=s.top(), s.pop();
                scc[x]=scc_cnt;
                vis[x]=2;
            }
            while(x!=pos);
        }
    }
    void run(Graph &G, int n)
    {
        for(int i=1;i<=n;i++)if(!vis[i])dfs(G,i);
    }
}tarjan;
vector<int> row[1000010], col[1000010];
bool check(int P)
{
    int i, j;
    G.clear(2*N);
    tarjan.clear(2*N);
    for(i=0;i<=1000000;i++)
        for(auto a:row[i])for(auto b:row[i])
            if(a!=b and abs(y[a]-y[b])<=2*P)G.adde(a+N,b);
    for(i=0;i<=1000000;i++)
        for(auto a:col[i])for(auto b:col[i])
            if(a!=b and abs(x[a]-x[b])<=2*P)G.adde(a,b+N);
    tarjan.run(G,2*N);
    for(i=1;i<=N;i++)if(tarjan.scc[i]==tarjan.scc[N+i])return false;
    return true;
}
int main()
{
    int i, j, l, r, mid;
    cin>>N;
    for(i=1;i<=N;i++)
    {
        cin>>x[i]>>y[i];
        row[x[i]].emplace_back(i);
        col[y[i]].emplace_back(i);
    }
    l=0, r=1000000;
    while(l<r)
    {
        mid=(l+r+1)>>1;
        if(check(mid))l=mid;
        else r=mid-1;
    }
    if(l==1000000)cout<<"UNLIMITED";
    else cout<<l;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值