BZOJ2428_均分数据_KEY
这道题可以用C++的random_shuffle屮过去。
random数列插入顺序,每次都插入数值和最小的那一组。
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; int N,M,a[25]; double ave,ans=2e9,t[25]; double get() { double tot=0; memset(t,0,sizeof t); for(int i=1;i<=N;i++){ int d,mx=2e9; for(int j=1;j<=M;j++)if(t[j]<mx)mx=t[j],d=j; t[d]+=a[i]; } for(int i=1;i<=M;i++) tot+=(ave-t[i])*(ave-t[i]); return tot; } int main() { srand(100000007); scanf("%d%d",&N,&M); for(int i=1;i<=N;i++)scanf("%d",&a[i]),ave+=a[i];ave/=M; for(int i=1;i<=600000;i++){ random_shuffle(a+1,a+N+1); ans=min(ans,get()); } printf("%.2lf",sqrt(ans/M)); return 0; }
这道题也可以用模拟退火。
设定一个初始温度,然后降温,降温的同时如果大于某个你设定的温度,即当前状态不稳定,进行贪心。
反之为稳定可以随机一个放到随机一个组里。
code:
#include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; int N,M,w[25],S=52867; double ans,res=2e9,t[25],ave,a[25]; void work(int x,int y) { t[w[x]]-=a[x]; t[y]+=a[x]; w[x]=y; } double get() { double tot=0; for(int i=1;i<=M;i++) tot+=(ave-t[i])*(ave-t[i]); return tot; } int main() { scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) scanf("%lf",&a[i]),ave+=a[i]; ave/=M; srand(12254687); while(S--){ memset(t,0,sizeof t); memset(w,0,sizeof w); for(int i=1;i<=N;i++) t[w[i]=rand()%M+1]+=a[i]; ans=get(); for(double Tempr=15000;Tempr>1;Tempr*=0.812){ int x=rand()%N+1,y=1,bef; if(Tempr<100)y=rand()%M+1; else for(int i=2;i<=M;i++)if(t[y]>t[i])y=i; bef=w[x]; work(x,y); double now=get(); if(now<ans||Tempr>rand()%15000)ans=now; else work(x,bef); } res=min(res,ans); } printf("%.2lf",sqrt(res/M)); return 0; }