洛谷.4252.[NOI2006]聪明的导游(提答 直径 随机化)
随机化 暴力:
随便从一个点开始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[N],Enum,H[N],nxt[M],to[M],f[N];
bool vis[N];
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[N];
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[N],Enum,H[N],nxt[M],to[M],_Enum,_H[N],_nxt[M],_to[M],Dgr[N],dgr[N],ans[N];
bool vis[N];
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;
}
洛谷.4252.[NOI2006]聪明的导游(提答 直径 随机化)的更多相关文章
- 洛谷 P2504 [HAOI2006]聪明的猴子
洛谷 P2504 [HAOI2006]聪明的猴子 题目描述 在一个热带雨林中生存着一群猴子,它们以树上的果子为生.昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水 ...
- 【洛谷4252】[NOI2006] 聪明的导游(提答题)
点此看题面 大致题意: 给你一张\(n\)个点.\(m\)条边的无向图,让你找出图上的一条不经过重复节点的最长路(提答+\(spj\)). 随机化乱搞 针对这种提答题,我们就要用随机化乱搞(Cptra ...
- 洛谷 P4397 [JLOI2014]聪明的燕姿 / TOPOI 测验1315, 问题E: 1935: 聪明的燕姿 解题报告
题目链接 : 1. 洛谷 2.topoi . 大致题意:输入一个数s,找出所有约数和为s的数 关于一个数的约数和求法: 一个>1的整数可以被分解为多个 质数 的乘方,设数 s = p1k1 * ...
- 洛谷 P4174 [NOI2006]最大获利 解题报告
P4174 [NOI2006]最大获利 题目描述 新的技术正冲击着手机通讯市场,对于各大运营商来说,这既是机遇,更是挑战.THU 集团旗下的 CS&T 通讯公司在新一代通讯技术血战的前夜,需要 ...
- 洛谷 P4297 [NOI2006]网络收费
P4297 [NOI2006]网络收费 题目背景 noi2006 day1t1 题目描述 网络已经成为当今世界不可或缺的一部分.每天都有数以亿计的人使用网络进行学习.科研.娱乐等活动.然而,不可忽视的 ...
- 洛谷—— P2504 [HAOI2006]聪明的猴子
P2504 [HAOI2006]聪明的猴子 题目描述 在一个热带雨林中生存着一群猴子,它们以树上的果子为生.昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上. ...
- 洛谷——P2504 [HAOI2006]聪明的猴子
P2504 [HAOI2006]聪明的猴子 题目描述 在一个热带雨林中生存着一群猴子,它们以树上的果子为生.昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上. ...
- 【洛谷p1314】聪明的质监员
聪明的质监员[题目链接] 有关算法: 二分答案: 但是你只二分答案是不够的,因为你check会炸,所以还要考虑前缀和: 首先假装我们的check已经写好了,main函数: int main() { n ...
- 洛谷P4204 [NOI2006]神奇口袋 数论
正解:数论 解题报告: 传送门 第一次用\(\LaTeX\)和\(markdown\),,,如果出了什么锅麻烦在评论跟我港句QAQ \(1)x_{i}\)可以直接离散 \(2)y_{i}\)的顺序对结 ...
随机推荐
- 弗罗贝尼乌斯範数(Frobenius norm)
弗罗贝尼乌斯範数 对 p = 2,这称为弗罗贝尼乌斯範数(Frobenius norm)或希尔伯特-施密特範数( Hilbert–Schmidt norm),不过后面这个术语通常只用于希尔伯特空间.这 ...
- python 面试题3
注:本面试题来源于网络. 1.python下多线程的限制以及多进程中传递参数的方式 python多线程有个全局解释器锁(global interpreter lock),这个锁的意思是任一时间只能有一 ...
- Java基础break、continue语句的用法
break适用范围:只能用于switch或者是循环语句中.当然可以用于增强for循环. break作用: 1. break用于switch语句的作用是结束一个switch语句. 2. break用于循 ...
- VMware 增加硬盘ubuntu
http://blog.csdn.net/Timsley/article/details/50742755
- Tslib步骤以及出现问题的解决方案【转】
转自:http://forum.eepw.com.cn/thread/267828/1 嵌入式设备中触摸屏使用非常广泛,但触摸屏的坐标和屏的坐标是不对称的,需要校准.校准广泛使用的是开源的tslib. ...
- 正则表达式基础->
描述:(grep) 正则表达式是一种字符模式,用于在查找过程中匹配指定的字符.在大多数程序里,正则表达式都被置于两个正斜杠之间,它匹配被查找的行中任何位置出现的相同模式 基础正则表达式 正则表达式 描 ...
- linux下快速安装emacs方法
背景 在公司工作的时候经常需要在很多服务器之间切换,而公司的服务器上一般都没emacs,因此总结一下快速安装emacs的方法. 最简单的是直接使用yum安装,但是有两个问题,一个是有的生产服务器直接没 ...
- python图片处理和matlab图片处理的区别
作者:波布兰链接:https://www.zhihu.com/question/28218420/answer/39904627来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明 ...
- SQL2008关于权限的解释
在SQL2008中我自己创建的一个登录名,可是那个登录名只可以用来登录,对数据库的操作什么都不能,连读取数据库都不可以.因为权限不够,只要把登录名的属性打开点击“服务器角色”,把public和sysa ...
- 使用mockito模拟静态方法
一.为什么要使用Mock工具 在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,远程服务, 文件系统等等). 而我们没法控制这些外部依赖的对象,为了解 ...