版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
众所周知,玄学是万能的
前言
此题正解为dfs,但我希望我的做法可以为您提供一种新的思路。
引入:random_shuffle函数
使用方法:
random_shuffle(a+1,a+n+1);
得到一个元素种类与原数组相同,但顺序被打乱的新数组。
测试如下:
时间复杂度:
正题
让我们回到本题,题目要求是在 人中选出一些人,使得他们之间没有有仇的人。
看一下数据范围,发现 ,但dfs+剪枝也是一个玄学的东西,不知道它能否过掉所有的数据点,那么我们就可以祭出我们的玄学随机大法——random_shuffle
做法
我们每次枚举一个选人的顺序,然后从头到尾选,如果能选,我们就选上这个人,并且将其仇敌全部标记,然后更新我们的答案。做一次的准确率太差,经过本人实测,重复次数开在 次左右即可做到既不超时(900+ms),又保证准确率。当然,如果脸白的话,重复次数 也是可能过的。
注意
由于本题存在多解但没有SPJ,所以用这种做法还需要判断一下字典序,最后取所有答案中字典序最大的输出。
下面献上我的代码
#include<bits/stdc++.h>
using namespace std;
int first[100005],nxt[100005],to[100005],tot=0;
void Add(int x,int y){
nxt[++tot]=first[x];
first[x]=tot;
to[tot]=y;
}
int n,m,a[105],vis[105],maxn=-1,ans[105];
bool pd(){
for(int i=1;i<=n;i++){
if(vis[i]<ans[i]) return 0;
if(vis[i]>ans[i]) return 1;
}
}
int main(){
srand(time(0));
cin>>n>>m;
for(int i=1;i<=n;i++){
a[i]=i;
}
for(int i=1;i<=m;i++){
int x,y;
cin>>x>>y;
Add(x,y);
Add(y,x);
}
for(int i=1;i<=200000;i++){
memset(vis,-1,sizeof(vis));
random_shuffle(a+1,a+n+1);
int num=0;
for(int i=1;i<=n;i++){
if(vis[a[i]]==-1){
num++,vis[a[i]]=1;
for(int e=first[a[i]];e;e=nxt[e]){
if(vis[to[e]]==-1) vis[to[e]]=0;
}
}
}
if(num>maxn){
maxn=num;
for(int i=1;i<=n;i++){
ans[i]=vis[i];
}
}
if(num==maxn){
if(pd()){
for(int i=1;i<=n;i++){
ans[i]=vis[i];
}
}
}
}
cout<<maxn<<endl;
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
}
后记
此算法并非正解,也有一定可能被卡掉,建议大家在正式考试时除非万不得已,尽量不要使用这种做法。