dfs计算途中所有联通块的数量,并计算其中是否有特殊点(炸弹)。

牛客暑期训练1 F dfs鸡玩炸弹人

炸鸡最近在 ɔiq平台上白嫖了一款游戏:《炸蛋人》。

《炸蛋人》的主角炸蛋人生活在一张n个结点(编号1到m条边的无向图上(图不一定联通),炸鸡可以控制炸蛋人进行两种操作:移动和放置炸蛋。具体说明如下。

移动:炸蛋人可以移动到当前所在结点通过一条边相连的相邻节点,但炸蛋人只能移动到没有炸蛋的结点。注意,尽管不能移动到有炸蛋的结点,但允许炸蛋人从一个当前有炸蛋的结点出发,移动到相邻没有炸蛋的结点。

放置炸蛋:炸蛋人在当前位置放置一枚炸蛋,炸蛋一经放置就会永久存在于图中(炸蛋全称为炸制金黄色的农家土鸡蛋,因此当然不会爆炸),每个位置可以放置多枚炸蛋。已知炸蛋人所在的无向图初始没有炸蛋,炸蛋人出现在了地图上的S点,炸鸡对炸蛋人进行了一系列的操作,炸蛋人最终停留在了T点。现在,给出无向图最终的情况,请你求出有多少种可能的起点终点方案(S,T),两种方案不同当且仅当它们的起点和终点至少有一个不同。若无合法方案输出0。

计算有炸弹的连通块的数量。在一个连通块内不论炸弹怎样分布,都可以达到目的。

若数量为0,直接sizisizisizjsizj;若为1,输出有炸弹连通块内的sizsiz。

dfs时,要先对dfs传入的点进行标记,然后在dfs,不然可能会漏点

#include<iostream>
#include<vector>

using namespace std;

typedef long long ll;



vector<int> g[100010];
bool st[100010];
int have_bomb,c[100010];
int n, m,sz;

void dfs(int u)
{
    if(c[u])
        have_bomb = 1;
    st[u] = true;
    sz++;
    for(auto a:g[u])
    if(!st[a])     dfs(a);
}

int main()
{
    cin>>n>>m;
    int u, v;
    for (int i = 0; i < m;i++)
    {
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }

    for (int i = 1; i <= n;i++)   scanf("%d", &c[i]);

    int bomb = 0,last_bomb=0;
    vector<ll> p_size;
    for (int i = 1; i <= n;i++)
    {
        if(!st[i])
        {
            sz=have_bomb = 0;
            dfs(i);
            bomb += have_bomb;
            p_size.push_back(sz);
            if(have_bomb) last_bomb = p_size.size()-1;
        }
    }

    if(bomb==0)
    {
        ll ans=0;
        for(auto a:p_size) ans+=(a*a);
        printf("%lld", ans);
    }
    else if(bomb==1)   printf("%lld", (ll)p_size[last_bomb] * p_size[last_bomb]);
    else   printf("%d", 0);
    return 0;
}
posted on 2023-01-29 12:04  rain_wind_read  阅读(34)  评论(0)    收藏  举报