BZOJ_3935_Rbtree

https://lydsy.com/JudgeOnline/problem.php?id=3935

分析:

  • 如果知道更改后的状态,那么代价和是否合法都能求出来
  • 对不合法的情况也设一个估价函数。
  • 随机这个01串,模拟退火即可。

代码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstdlib>
using namespace std;
#define N 550
typedef long long ll;
#define inf 0x3f3f3f3f
typedef double f2;
f2 Rand() {
    return f2(rand())/RAND_MAX;
}
int head[N],to[N<<1],nxt[N<<1],n,cnt,w[N],X,val[N<<1];
ll dis[N][N];
int len[N],vec[N][N];
inline void add(int u,int v,int w) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
void dfs(int x,int y,int rt) {
    int i;
    for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
        dis[rt][to[i]]=dis[rt][x]+val[i];
        dfs(to[i],x,rt);
    }
}
struct A {
    int a[N],ans; 
    A() {ans=inf;}
}ANS,TMP;
int check(const A &x) {
    int i,j,re=0;
    for(i=1;i<=n;i++) if(x.a[i]==0) {
        int flg=0;
        for(j=1;j<=len[i];j++) if(x.a[vec[i][j]]) {
            flg=1; break;
        }
        if(!flg) re++;
    }
    return re;
}
void calc(A &x) {
    int i,t=0;
    for(i=1;i<=n;i++) t+=(x.a[i]!=w[i]);
    int tmp=check(x);
    if(tmp) x.ans=tmp*2+(n>>1);
    else x.ans=(t>>1);
    if(x.ans<ANS.ans) ANS=x;
}
int t0[N],t1[N],l1,l0;
A kuo(const A &x,int y) {
    A re=x;
    int i;
     
    for(i=1;i<=y;i++) {
        int l=rand()%l1+1,r=rand()%l0+1;
        swap(re.a[t1[l]],re.a[t0[r]]);
    }
    return re;
}
void orztuihuo(f2 BG,f2 ED,f2 d) {
    calc(TMP);
    A now=TMP;
    l0=l1=0;
    int i;
    for(i=1;i<=n;i++) {
        if(!now.a[i]) t0[++l0]=i;
        else t1[++l1]=i;
    }
    for(;BG>ED;BG*=d) {
        A nxt=kuo(now,max(1.0,BG));
        calc(nxt);
        if(nxt.ans < now.ans || Rand() < exp((now.ans-nxt.ans)/BG)) {
            now=nxt;
            l0=l1=0;
            for(i=1;i<=n;i++) {
                if(!now.a[i]) t0[++l0]=i;
                else t1[++l1]=i;
            }
        }
    }
    for(i=1;i<=10000;i++) {
        A nxt=kuo(ANS,1);
        calc(nxt);
    }
}
int main() {
    srand(114514); rand();
    scanf("%d%d",&n,&X);
    int i,j;
    for(i=1;i<=n;i++) scanf("%d",&w[i]);
    int x,y,z;
    for(i=1;i<n;i++) {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z); add(y,x,z);
    }
    for(i=1;i<=n;i++) dfs(i,0,i);
    for(i=1;i<=n;i++) for(j=1;j<=n;j++) if(i!=j&&dis[i][j]<=X) {
        vec[i][++len[i]]=j;
    }
    ANS.ans=inf;
    int sw=0;
    for(i=1;i<=n;i++) TMP.a[i]=w[i],sw+=w[i];
    random_shuffle(TMP.a+1,TMP.a+n+1);
 
    if(n<=100) orztuihuo(50,0.001,0.999);
    else if(sw>100) orztuihuo(100,0.1,0.999998);
    else orztuihuo(100,0.01,0.99993);
    // for(i=1;i<=n;i++) printf("%d ",ANS.a[i]); puts("");
    printf("%d\n",ANS.ans>n?-1:ANS.ans);
}

猜你喜欢

转载自www.cnblogs.com/suika/p/10015396.html
今日推荐