你发现 $n\leq 26$,直接考虑随机化乱搞。
由于这道题的数据比较强,所以不能硬随,要加一点优化。
第一步,你随机一些序列,取其中最优的序列开始交换。
在随机交换的过程中,为了减少陷入局部最优解的概率,在被拒绝了一定次数之后,随机交换一部分的决策,这样就会让你的随机化贪心正确率更高。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include<bits/stdc++.h> using namespace std; int n,m,a[105],ans[105],v[105]; vector<int> g[105]; mt19937 rd(19530615); inline int calc(){ int as=0; for(int i=1;i*2<=n;++i) for(int j:g[a[i]])as+=v[j]; return as; } inline int calc2(){ int as=0; for(int i=1;i*2<=n;++i) for(int j:g[ans[i]])as+=v[j]; return as; } int main(){ cin>>n>>m; for(int i=1;i<=m;++i){ int x,y;cin>>x>>y; g[x].push_back(y); g[y].push_back(x); } for(int i=1;i<=n;++i)a[i]=i; int sans=1e7; for(int i=1;i<=20;++i){ shuffle(a+1,a+n+1,rd); for(int i=1;i<=n/2;++i)v[a[i]]=0; for(int i=n/2+1;i<=n;++i)v[a[i]]=1; int sum=calc(); if(sans>sum){ sans=sum; for(int i=1;i<=n;++i)ans[i]=a[i]; } } for(int i=1;i<=n/2;++i)v[ans[i]]=0; for(int i=n/2+1;i<=n;++i)v[ans[i]]=1; for(int i=1;i<=n;++i)a[i]=ans[i]; int cnt=0; while(1.0*clock()/CLOCKS_PER_SEC<=0.48){ int x=rd()%(n/2)+1,y=rd()%(n/2)+n/2+1; swap(a[x],a[y]);swap(v[a[x]],v[a[y]]); int sum=calc(); if(sans>sum){sans=sum;for(int i=1;i<=n;++i)ans[i]=a[i];} else swap(a[x],a[y]),swap(v[a[x]],v[a[y]]),++cnt; if(cnt%100==0){ for(int i=1;i<=20;++i){ int x=rd()%(n/2)+1,y=rd()%(n/2)+n/2+1; swap(a[x],a[y]);swap(v[a[x]],v[a[y]]); } } } while(1.0*clock()/CLOCKS_PER_SEC<=0.98){ int x=rd()%(n/2)+1,y=rd()%(n/2)+n/2+1; swap(a[x],a[y]);swap(v[a[x]],v[a[y]]); int sum=calc(); if(sans>sum){sans=sum;for(int i=1;i<=n;++i)ans[i]=a[i];} else swap(a[x],a[y]),swap(v[a[x]],v[a[y]]),++cnt; if(cnt%80==0){ for(int i=1;i<=20;++i){ int x=rd()%(n/2)+1,y=rd()%(n/2)+n/2+1; swap(a[x],a[y]);swap(v[a[x]],v[a[y]]); } } } for(int i=1;i*2<=n;++i)cout<<ans[i]<<' '; cout<<'\n'; return 0; }
|