bzoj4670: 佛罗里达
这题直接随机化+贪心就可以爆踩过去,我加了个退火增加容错率而已。。。。其实你随机的次数够多根本不需要。。。
然后来自肉丝哥哥的正经做法:
先钦定D(A)>D(B),那么可以枚举D(A),然后再去二分D(B),强行2-sat判就可以做到O(n^4logn)了
再考虑优化,把边按大到小排序,对于当前枚举D(A)枚举到的边,假如它在原图的一个偶环里面,那么在2-sat中一定也会和偶环里的一半点放在放在同一侧。而这些点的边之前已经尝试计算答案了,当前不可能成为最优解。假如处于一个奇环里面,进行完以后2-sat里面一定会有奇环导致不合法。这样就只会有O(n)条边贡献
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; inline double dbrand(){return (double)(rand()%10000)/10000.0;} int n,Au,Av,Bu,Bv,ans; int mp[310][310],bel[310]; int atp,a[310],btp,b[310],au,av,bu,bv; int calc() { atp=0,btp=0; for(int i=1;i<=n;i++) if(bel[i]==0)a[++atp]=i; else b[++btp]=i; int A=-1,B=-1; for(int i=1;i<=atp;i++) for(int j=i+1;j<=atp;j++) if(mp[a[i]][a[j]]>A)A=mp[a[i]][a[j]],au=a[i],av=a[j]; for(int i=1;i<=btp;i++) for(int j=i+1;j<=btp;j++) if(mp[b[i]][b[j]]>B)B=mp[b[i]][b[j]],bu=b[i],bv=b[j]; if(A==-1)A=0; if(B==-1)B=0; if(A+B<ans)ans=A+B; return A+B; } void annealing() { double T=1e5; int num=calc();Au=au,Av=av,Bu=bu,Bv=bv; while(T>1e-3) { for(int i=1;i<=1000;i++) { if(i%10==0) { bool bk=false; int cc=0; for(int p=0;p<=3;p++) { int x; if(p==0)x=Au; else if(p==1)x=Av; else if(p==2)x=Bu; else if(p==3)x=Bv; bel[x]^=1; int ddd=calc(); if(ddd<num) num=ddd,Au=au,Av=av,Bu=bu,Bv=bv; else bel[x]^=1,cc++; T*=0.97; } if(cc==4)break; } int p=rand()%4; int x; if(p==0)x=Au; else if(p==1)x=Av; else if(p==2)x=Bu; else if(p==3)x=Bv; bel[x]^=1; int ddd=calc(); if(ddd<num) num=ddd,Au=au,Av=av,Bu=bu,Bv=bv; else bel[x]^=1; T*=0.97; } for(int i=1;i<=100;i++) { int x=rand()%n+1; bel[x]^=1; int ddd=calc(); int delta=ddd-num; if(ddd<num||exp(delta/T)>=dbrand()) num=ddd,Au=au,Av=av,Bu=bu,Bv=bv; else bel[x]^=1; T*=0.97; } } for(int i=1;i<=100;i++) { int x=rand()%n+1; bel[x]^=1; int ddd=calc(); bel[x]^=1; } } int main() { srand(2003); while(scanf("%d",&n)!=EOF) { int mx=0,sx; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { scanf("%d",&mp[i][j]),mp[j][i]=mp[i][j]; if(mx<mp[i][j]) { sx=mx; mx=mp[i][j]; } else sx=max(sx,mp[i][j]); } ans=sx; for(int i=1;i<=20;i++) { for(int j=1;j<=n;j++)bel[j]=rand()%2; annealing(); } printf("%d\n",ans); } return 0; }
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int maxn=250+10; const int maxp=2*maxn; int n; struct edge{int x,y,d;}e[maxn*maxn];int elen; bool cmp(edge e1,edge e2){return e1.d>e2.d;} namespace DISSCUSS { int fa[maxn]; int findfa(int x) { if(x==fa[x])return x; fa[x]=findfa(fa[x]);return fa[x]; } vector<int>vec[maxn]; int ed,dis; void dfs(int x,int fr,int d) { if(dis!=-1)return ; if(x==ed){dis=d;return ;} for(int i=0;i<vec[x].size();i++) { int y=vec[x][i]; if(y!=fr)dfs(y,x,d^1); } } int getflag(int x,int y) { int fx=findfa(x),fy=findfa(y); if(fx!=fy) { fa[fx]=fy; vec[x].push_back(y); vec[y].push_back(x); return 1; } else { dis=-1,ed=y;dfs(x,0,1); if(dis==1)return 2; else return 0; } } void pre() { for(int i=1;i<=n;i++) fa[i]=i,vec[i].clear(); } } namespace TWOSAT { struct node { int x,y,next; }a[2*4*maxn*maxn];int len,last[maxp]; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } int z,dfn[maxp],low[maxp]; int top,sta[maxp];bool v[maxp]; int cnt,bel[maxp]; void SCC(int x) { dfn[x]=low[x]=++z; sta[++top]=x;v[x]=true; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(dfn[y]==0) { SCC(y); low[x]=min(low[x],low[y]); } else if(v[y]==true) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { int i; cnt++; do { i=sta[top];top--; v[i]=false; bel[i]=cnt; }while(i!=x); } } void composition(int da,int db) { len=0;memset(last,0,sizeof(last)); for(int i=1;i<=elen;i++) { if(e[i].d>da)ins(e[i].x,e[i].y+n),ins(e[i].y,e[i].x+n); if(e[i].d>db)ins(e[i].x+n,e[i].y),ins(e[i].y+n,e[i].x); } } bool main(int da,int db) { composition(da,db); z=top=cnt=0; memset(dfn,0,sizeof(dfn)); memset(v,false,sizeof(v)); for(int i=1;i<=2*n;i++) if(dfn[i]==0)SCC(i); for(int i=1;i<=n;i++) if(bel[i]==bel[i+n])return false; return true; } } bool check(int da,int db){return TWOSAT::main(da,db);} int main() { while(scanf("%d",&n)!=EOF) { elen=0; for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) scanf("%d",&e[++elen].d),e[elen].x=i,e[elen].y=j; sort(e+1,e+elen+1,cmp); e[elen+1].d=0; DISSCUSS::pre(); int ans=2147483647; for(int i=1;i<=elen;i++) { int flag=DISSCUSS::getflag(e[i].x,e[i].y); if(flag>=1) { int el=i,er=elen+1,j; while(el<=er) { j=(el+er)/2; if(check(e[i].d,e[j].d)) { ans=min(ans,e[i].d+e[j].d); el=j+1; } else er=j-1; } if(flag==2)break; } } printf("%d\n",ans); } return 0; }
pain and happy in the cruel world.