• 潜入苏拉玛(BFS+构造)


    问题 A: 潜入苏拉玛

    时间限制: 1 Sec 内存限制: 128 MB

    题目描述

    你接到了⼀个任务,让你潜⼊苏拉玛城,和线⼈取得联络。苏拉玛的地图是⼀张N个点M条边的⽆向图,每个点表⽰苏拉玛城的⼀个路⼜,每条边表⽰苏拉玛内的⼀条道路,长度都是1。你从S号节点出发,线⼈在T号节点。
    由于苏拉玛城内都是夜之⼦的哨兵,你需要假⾯伪装才能在苏拉玛的道路上⾏⾛。你的伪装只能坚持你⾛完K段道路不被发现,幸好在苏拉玛城内还有P个内应(分别在节点ai上),他们可以修复你的伪装,让它恢复到刚开始的状态。
    你想知道K⾄少需要是多少,才能让你成功找到线⼈。

    输入

    第⼀⾏⼀个正整数CAS表⽰测试数据组数。
    每组测试数据第⼀⾏有三个数N,M,P如上⽂所述,第⼆⾏P个数表⽰内应的位置。接下来M⾏,每⾏2个数表⽰⼀条边。最后⼀⾏S和T表⽰你开始的节点和你的⽬标节点。

    输出

    对于每组数据:如果你⽆法到达线⼈那⾥,输出-1,否则输出最⼩的K。

    样例输入

    2
    6 6 3
    1 3 6
    1 2
    2 3
    4 2
    5 6
    4 5
    3 4
    1 6
    7 10 3
    1 3 4
    1 2
    4 2
    7 5
    4 5
    7 1
    2 5
    7 2
    3 7
    3 2
    5 1
    4 6

    样例输出

    3
    -1

    提示

    对于100%的数据,1≤K,S,T≤N≤100000,1≤M≤150000,1≤CAS≤5。

    思路:

    把起点、终点、内应都视为原点。
    假设答案一定是偶数,也就是从(S)(T)经过两个相邻原点的距离都(le 2K)
    这样问题就转化为从每个原点出发(bfs) 各走(k)步,走出的点集是(S,T)联通。
    如果(S=T,ans=0)。否则,
    每次将相邻的点加入,重新(bfs),相当于(ans+=2)
    但是答案显然有奇数的情况,我们只需在每条边中间加一条中间点,也就是说如果(i-j)有一条边,改为(i-x,x-j)个有一条边。这样就保证了结果一定是偶数,最后把答案(div 2)即可。
    注意到是无向图,判连通性可以用并查集,加上线性的遍历,最终复杂度就是(O(nlogn))

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3, "Ofast", "inline")
    #include "bits/stdc++.h"
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll,ll> pii;
    const int N=1e6+5;
    const ll mod=1e9+7;
    const double eps=1e-5;
    //const double pi=acos(-1);
    vector<int>g[N];
    int vis[N],f[N];
    int getf(int x)
    {
        return f[x]==x?x:f[x]=getf(f[x]);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        int _;
        cin>>_;
        while(_--)
        {
            int n,m,k;
            cin>>n>>m>>k;
            queue<int>q,p;
            memset(vis,0,sizeof vis);
            for(int i=1;i<=m*2;i++) g[i].clear(),f[i]=i;
            for(int j=0,x;j<k;j++)
            {
                cin>>x;
                if(!vis[x])
                    q.push(x),vis[x]=1;
            }
            k=n+1;
            while(m--)
            {
                int u,v;
                cin>>u>>v;
                g[u].push_back(k);
                g[k].push_back(u);
                g[k].push_back(v);
                g[v].push_back(k);
                k++;
            }
            int x,y;
            cin>>x>>y;
            if(!vis[x]) q.push(x),vis[x]=1;
            if(!vis[y]) q.push(y),vis[y]=1;
            int ans=0;
            while(1)
            {
                ans++;
                if(q.empty())
                {
                    ans=-1;break;
                }
                while(!q.empty())
                {
                    int u=q.front();q.pop();
                    for(auto v:g[u])
                    {
                        int uu=getf(u),vv=getf(v);
                        if(uu>vv) swap(uu,vv);
                        f[vv]=uu;
                        if(vis[v]) continue;
                        p.push(v);
                        vis[v]=1;
                    }
                }
                if(getf(x)==getf(y))
                    break;
                while(!p.empty())
                {
                    q.push(p.front());p.pop();
                }
    
            }
            cout<<ans<<'
    ';
    
        }
        return 0;
    }
    
  • 相关阅读:
    Block为什么使用Copy?
    iOS运行时,如何增加成员变量
    安卓长按交互onCreateContextMenu的简单 用法
    iOS 检查版本号的代码
    git的基本使用
    svn的使用
    const 关键字及作用
    常见的内存分配
    保存字符串的方法
    指针的总结一(指针的定义)
  • 原文地址:https://www.cnblogs.com/Suiyue-Li/p/12838132.html
Copyright © 2020-2023  润新知