洛谷.4252.[NOI2006]聪明的导游(提答 直径 随机化)
2018-05-02 18:19
162 查看
题目链接
随机化 暴力:
随便从一个点开始DFS,每次从之前得到的f[i]最大的子节点开始DFS。f[i]为从i开始(之前)能得到的最大答案。
要注意的是f[i]应当有机会从更小的答案更新,
9.10求直径。
就82分了。
本来想的SPFA啥的也不对。。正解思路是这的。
正解:
可以先随机生成一棵树,然后去求它的直径。
想要这棵树的直径尽量大,它上面的点的度数应尽量小(要不大概就是很多分叉那样)。
枚举/随机一个根节点x,从它开始DFS,每次优先走度数最小的点v(注意把它相连的点的度数-1),连树上的边x->v。
DFS完这个度数最小的点v后,可以从x再走其它未访问的点,扩展树。
随机化 暴力:
随便从一个点开始DFS,每次从之前得到的f[i]最大的子节点开始DFS。f[i]为从i开始(之前)能得到的最大答案。
要注意的是f[i]应当有机会从更小的答案更新,
9.10求直径。
就82分了。
本来想的SPFA啥的也不对。。正解思路是这的。
#include <ctime> #include <cstdio> #include <cctype> #include <vector> #include <cstring> #include <algorithm> #define gc() getchar() const int N=10005,M=2e4+5; int n,m,Max,pos,A ,Enum,H ,nxt[M],to[M],f ; bool vis ; std::vector<int> ans,tmp,ANS; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } inline void AddEdge(int u,int v){ to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum; to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum; } void DFS(int x) { vis[x]=1, tmp.push_back(x); int way=0; for(int i=H[x]; i; i=nxt[i]) if(!vis[to[i]]&&f[way]<f[to[i]]) way=to[i]; if(way) DFS(way); } void Solve() { memset(f,0,sizeof f); for(int t=500; t; --t) for(int i=1; i<=n; ++i) { memset(vis,0,sizeof vis), tmp.clear(), DFS(i); if(tmp.size()>ans.size()) ans=tmp; // if(tmp.size()>f[i]) f[i]=tmp.size(); if(tmp.size()>f[i]||rand()%15==0) f[i]=tmp.size(); } if(ans.size()>ANS.size()) ANS=ans; } namespace Spec { int Max,v,pre ; void DFS(int x,int f,int d) { if(d>Max) Max=d, v=x; for(int i=H[x]; i; i=nxt[i]) if(to[i]!=f) pre[to[i]]=x, DFS(to[i],x,d+1); } void Solve() { Max=0, DFS(1,1,1); int u=v; Max=0, DFS(v,v,1); printf("%d\n%d\n",Max,v); while(v!=u) printf("%d\n",v=pre[v]); } } int main() { // freopen("guide.in","r",stdin); // freopen("guide.out","w",stdout); srand(time(NULL)); n=read(),m=read(); for(int i=1; i<=m; ++i) AddEdge(read(),read()); // Spec::Solve(); return 0;//9.10 for(int T=1; T<=15; ++T) Solve(); printf("%d\n",ANS.size()); for(int i=0; i<ANS.size(); ++i) printf("%d\n",ANS[i]); return 0; }
正解:
可以先随机生成一棵树,然后去求它的直径。
想要这棵树的直径尽量大,它上面的点的度数应尽量小(要不大概就是很多分叉那样)。
枚举/随机一个根节点x,从它开始DFS,每次优先走度数最小的点v(注意把它相连的点的度数-1),连树上的边x->v。
DFS完这个度数最小的点v后,可以从x再走其它未访问的点,扩展树。
#include <ctime> #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define gc() getchar() const int N=10005,M=2e4+5; int n,m,Max,V,pre ,Enum,H ,nxt[M],to[M],_Enum,_H ,_nxt[M],_to[M],Dgr ,dgr ,ans ; bool vis ; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } inline void AddEdge(int u,int v){ ++Dgr[u], to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum; ++Dgr[v], to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum; } inline void AddTree(int u,int v){ _to[++_Enum]=v, _nxt[_Enum]=_H[u], _H[u]=_Enum; _to[++_Enum]=u, _nxt[_Enum]=_H[v], _H[v]=_Enum; } void Build(int x) { vis[x]=1; int way=0; for(int i=H[x]; i; i=nxt[i]) --dgr[to[i]]; for(int i=H[x]; i; i=nxt[i]) if(!vis[to[i]]&&(dgr[way]>dgr[to[i]]||(dgr[way]==dgr[to[i]]&&rand()&1))) way=to[i]; // if(!vis[to[i]]&&dgr[way]>dgr[to[i]]) way=to[i];//略不对 if(way) AddTree(x,way), Build(way); for(int i=H[x]; i; i=nxt[i]) if(!vis[to[i]]) AddTree(x,to[i]), Build(to[i]); } void DFS(int x,int f,int d) { if(d>Max) Max=d, V=x; for(int i=_H[x]; i; i=_nxt[i]) if(_to[i]!=f) pre[_to[i]]=x, DFS(_to[i],x,d+1); } void Solve(int i) { _Enum=0, memset(_H,0,sizeof _H); memset(vis,0,sizeof vis), memcpy(dgr,Dgr,sizeof dgr), Build(i); Max=0, DFS(i,i,1); int u=V; Max=0, DFS(u,u,1); if(Max>ans[0]){ ans[ans[0]=Max]=V; while(V!=u) ans[--ans[0]]=V=pre[V]; ans[0]=Max; } } int main() { // freopen("guide.in","r",stdin); // freopen("guide.out","w",stdout); srand(time(NULL)); n=read(),m=read(); for(int i=1; i<=m; ++i) AddEdge(read(),read()); Dgr[0]=1000000; for(int T=10000; T; --T) Solve(rand()%n+1);//还是要多次 // for(int i=1; i<=n; ++i) Solve(i); printf("%d\n",ans[0]); for(int i=1; i<=ans[0]; ++i) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- 洛谷 1314||NOIP 2011 聪明的质检员 二分 解题报告
- 洛谷P1314 [NOIP2011提高组Day2T2] 聪明的质监员
- 洛谷1314 聪明的质监员
- 【NOI2006】聪明的导游
- 洛谷——P1314 聪明的质监员
- 洛谷 P1314 聪明的质监员
- 【NOI2006】聪明的导游
- 洛谷 P1314 [NOIP2011 D2T2] 聪明的质监员
- 洛谷 [P1314] 聪明的质检员(NOIP2011 D2T2)
- 洛谷P2504 [HAOI2006]聪明的猴子
- 洛谷 P1314 聪明的质检员
- 洛谷 P1314 聪明的质监员
- 【搜索】【随机化贪心】【NOI2006】聪明的导游
- 【NOI2006】 聪明的导游
- AC日记——聪明的质监员 洛谷 P1314
- 洛谷 P1314 聪明的质监员【二分+前缀和】
- 洛谷P1314 聪明的质监员
- 二分查找前缀和(洛谷1314聪明的质监员NOIP2011提高组)
- [NOIP2011] 提高组 洛谷P1314 聪明的质监员
- 洛谷 P1949 聪明的打字员 [NOI导刊2011提高(10)] (bfs+剪枝)