【L2-025 分而治之】天梯赛L2详细解答

该博客讨论了一种利用图的邻接表和深度优先搜索(DFS)解决城市摧毁问题的方法。在无向图中,如果摧毁特定城市后,所有城市不再连通,则认为策略可行。原始实现使用邻接矩阵,但因效率和内存限制改用邻接表。通过标记已摧毁城市并检查剩余未摧毁城市的邻接城市是否全被摧毁,可以判断是否达到目标。正确实现避免了超时和内存超限,提高了算法效率。
摘要由CSDN通过智能技术生成

天梯赛L2-025 分而治之

题目详情:

在这里插入图片描述
在这里插入图片描述
输入样例:

10 11
8 7
6 8
4 5
8 4
8 1
1 2
1 4
9 8
9 1
1 10
2 4
5
4 10 3 8 4
6 6 1 7 5 4 9
3 1 8 4
2 2 8
7 9 8 7 6 5 4 2

输出样例:

NO
YES
YES
NO
NO

思路:

题目的意思:按照方案如果,摧毁完所给的城市,所有的城市之间都不连接了就算YES
1、建立个图,然后是如果连接权值为1,不连接的话全局变量权值默认为0,但是有个问题,破坏原图后,必须得修复原图,所以破坏后,权值变为-1,以便下次恢复。但是这个样子超时了!!!就算不超时,内存也超限了。
2、所以换个思路:
用vector容器来存图(相当于邻接表),用visit数组来表示是否被摧毁(访问),如果一个城市被摧毁(访问)的话,那么visit[] = true;那么通过邻接表就可以知道这个城市已经被摧毁了。因为遍历visit[]的复杂度是O(n),并且更容易恢复,即不会超时和超限
3、最后什么情况下是YES呢:破坏完所给的城市,访问没有被摧毁城市的邻接城市,如果访问的邻接城市的visit都是true,那么就算YES,否则NO

详细代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 10000 + 5;
vector<int>G[maxn];
bool visit[maxn];//是否被摧毁(访问)
int n,m,k,Np;

int main()
{
    cin>>n>>m;
    for(int i=0; i<m; i++)//初始化邻接表,
    {
        int x,y;
        cin>>x>>y;
        G[x].push_back(y);//一个是有向图的邻接表
        G[y].push_back(x);//两个就是无向图了,访问是否有边就简单了
    }
    cin>>k;
    while(k--)
    {
        memset(visit,false,sizeof(visit));//每次检测方法是否可行的时候,都要初始化一下,这个比恢复图快了好多
        cin>>Np;
        for(int i=0; i<Np; i++)//输入被摧毁的城市
        {
            int temp;
            cin>>temp;
            visit[temp] = true;//被摧毁就是true
        }
        int flag = 1;
        for(int i=1; i<=n; i++)
        {
            if(!visit[i])//访问没有被摧毁的城市
            {
                for(int j=0; j<G[i].size(); j++)//访问没有被摧毁的城市的邻接表
                {
                    if(!visit[G[i][j]])//如果存在没有被访问的城市,那么证明这俩城市存在一条边
                    {
                        flag = 0;
                        break;
                    }
                }
            }
            if(!flag)
                break;
        }
        if(flag)
            cout<<"YES\n";
        else
            cout<<"NO\n";
    }
}

知识总结:

最后给大家展示一下错误示范:

const int maxn = 10000 + 5;
int G[maxn][maxn];
int n,m,k,Np;
bool dfs()//判断摧毁城市后,是否还连通
{
    int flag = 1;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            if(G[i][j] == 1)
                flag = 0;
        }
    }
    if(flag)
        return true;
    else
        return false;
}
int main()
{
    cin>>n>>m;
    for(int i=0; i<m; i++)
    {
        int x,y;
        cin>>x>>y;
        G[x][y] = G[y][x] = 1;
    }
    cin>>k;
    int temp[maxn];
    for(int i=0; i<k; i++)
    {
        cin>>Np;
        for(int j=0; j<Np; j++)
        {
            cin>>temp[j];
            for(int l=1; l<=n; l++)//破坏城市
            {
                if(G[temp[j]][l] == 1)
                    G[temp[j]][l] = G[l][temp[j]] = -1;
            }
        }
        if(dfs())
            cout<<"YES\n";
        else
            cout<<"NO\n";
        for(int j=0; j<Np; j++)//恢复原图
        {
            for(int l=1; l<=n; l++)
            {
                if(G[temp[j]][l] == -1)
                    G[temp[j]][l] = G[l][temp[j]] = 1;
            }
        }
    }
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值