1013 Battle Over Cities (25分)

题意

给定一个无向图并规定,当删除图中的某个顶点时,将会同时把与之连接的边一起删除。接下来给出k个查询,每个查询给出一个欲删除的顶点编号,求删除该顶点(和与其连接的边)后需要增加多少条边,才能使图变为连通(注: k次查询均在原图上进行)。

思路

注意是无向图

上来直接写了个暴力的代码,改了无向图的bug后交一发直接AC了???

暴力思路挺简单的,分别删除(1~n)号点后剩余的连通块数,不必真的删除,每次访问删除点时跳过就好了,然后每次的答案就是连通块数减一。

不过数据范围确实小,求连通块的复杂度是:(mathcal O(n+m)),这样总的复杂度就是(mathcal O(qm))(color{green}{AcWing})上给的范围是(3500000)

const int N=1010;
vector<int> g[N];
bool vis[N];
int n,m,q;

void dfs(int u,int x)
{
    vis[u]=true;
    for(int i=0;i<g[u].size();i++)
    {
        int j=g[u][i];
        if(j == x || vis[j]) continue;
        dfs(j,x);
    }
}

int main()
{
    cin>>n>>m>>q;

    while(m--)
    {
        int a,b;
        cin>>a>>b;
        g[a].pb(b);
        g[b].pb(a);
    }

    while(q--)
    {
        memset(vis,0,sizeof vis);
        int x;
        cin>>x;

        int cnt=0;
        for(int i=1;i<=n;i++)
            if(!vis[i] && i != x)
            {
                dfs(i,x);
                cnt++;
            }

        cout<<cnt-1<<endl;
    }
    //system("pause");
    return 0;
}

当然,既然是求连通块,那怎么能少的了并查集捏。只要不合并删除点和领接点就行了。

const int N=1010;
struct Edge{
    int a,b;
}e[N*N];
int p[N];
int n,m,q;

int find(int x)
{
    if(x != p[x]) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    cin>>n>>m>>q;

    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        e[i]={a,b};
    }

    while(q--)
    {
        for(int i=1;i<=n;i++) p[i]=i;
        
        int x;
        cin>>x;

        int cnt=0;
        for(int i=0;i<m;i++)
        {
            int a=e[i].a,b=e[i].b;
            if(a != x && b != x)
            {
                int pa=find(a),pb=find(b);
                p[pa]=pb;
            }
        }
        
        for(int i=1;i<=n;i++)
            if(p[i] == i && i != x)
                cnt++;
        cout<<cnt-1<<endl;
    }
    //system("pause");
    return 0;
}