BZOJ_3935_Rbtree
阿新 • • 發佈:2018-11-25
wap calc add break 1.0 swap uri 函數 can
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); }
BZOJ_3935_Rbtree