天梯赛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;
}
}
}
}