【NOI2006】聪明的导游

题面

洛谷

题目描述

小佳最近迷上了导游这个工作,一天到晚想着带游客参观各处的景点。正好 M 市在举行 NOI,来参观的人特别的多。不少朋友给小佳介绍了需要导游的人。

M 市有nnn 个著名的景点,小佳将这些景点从111 至nnn 编号。有一些景点之间存在双向的路。小佳可以让游客们在任何一个景点集合,然后带着他们参观,最后也可以在任何一个景点结束参观。不过,来参观的游客们都不愿去已经参观过的地方。所以,小佳不能带游客们经过同一个景点两次或两次以上。

小佳希望你帮助他设计一个方案, 走可行的路线, 带游客们参观尽可能多的地方。

输入输出格式

输入格式:

输入文件为 guide1.in~guide10.in,第一行为两个整数n,mn,mn,m ,分别表示景点数和路的条数。接下来mmm 行,每行两个整数a,ba,ba,b ,表示景点aaa 和景点bbb 之间有一条双向路。

输出格式:

你需要将答案输出到 guide1.out~guide10.out 中,guide?.out 为对应 guide?.in

的答案。输出的第一行为ppp ,表示你能找到的路径所经过的景点个数。接下来ppp 行,每行一个整数,按顺序表示你所找到的路径上的每一个景点。

题解

数据什么的到洛谷上去下载

也到洛谷上提交

回归题目

看到题答题,一般都是怎么想着怎么乱搞

于是我YY了一种乱搞方法:

每次从任意一个点开始

访问之前计算出来的答案中最大的那个儿子

知道走不了为止

然后把这个链的长度设为当前为止的答案

然后重复多次这个过程,

结合1,2两个点的打爆力,第10个点的树形\(dp\)

于是拿到了\(86\)分

附上我一顿乱搞的代码(因为代码很乱搞,所以代码也很乱)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 11000
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n,m;
bool vis[MAX];
struct Line{int v,next;}e[MAX<<2];
int h[MAX],cnt=1;
vector<int> ans,st;
int du[MAX];
int f[MAX],ret=0,dep[MAX],fa[MAX];
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
void init()
{
memset(h,0,sizeof(h));cnt=1;
memset(f,0,sizeof(f));memset(dep,0,sizeof(dep));
memset(fa,0,sizeof(fa));ret=0;
for(int i=1;i<=n;++i)du[i]=i;
}
int getf(int x){return x==du[x]?x:du[x]=getf(du[x]);}
void dp(int u,int ff)
{
f[u]=1;dep[u]=dep[ff]+1;fa[u]=ff;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(v==ff)continue;
dp(v,u);
ret=max(ret,f[u]+f[v]);
f[u]=max(f[u],f[v]+1);
}
}
int bfn[MAX];
int bfs(int S)
{
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(S);
int ret,tim=0;
while(!Q.empty())
{
int u=Q.front();Q.pop();
ret=u;vis[u]=true;bfn[u]=++tim;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(vis[v])continue;
vis[v]=true;Q.push(v);
}
}
return ret;
}
vector<int> ans1,ans2;
void jump(int u,int v)
{
ans1.clear();ans2.clear();
if(dep[u]<dep[v])swap(u,v);
while(dep[u]!=dep[v])ans1.push_back(u),u=fa[u];
while(u!=v)
{
ans1.push_back(u);ans2.push_back(v);
u=fa[u];v=fa[v];
}
ans1.push_back(v);
for(int i=ans2.size()-1;i>=0;--i)ans1.push_back(ans2[i]);
if(ans1.size()>ans.size())ans=ans1;
}
struct edge{int u,v;}E[MAX<<1];
void Build()
{
for(int i=1;i<=m;++i)
{
int u=E[i].u,v=E[i].v;
if(getf(u)==getf(v))continue;
Add(u,v);Add(v,u);
du[getf(u)]=getf(v);
}
}
int son[MAX],sum,Ans[MAX];
bool cmp(int a,int b){if(Ans[a]!=Ans[b])return Ans[a]<Ans[b];else return rand()%2;}
int main()
{
srand(time(NULL));
freopen("guide4.in","r",stdin);
freopen("guide4.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
for(int T=1;T<=1000;++T)
for(int i=1;i<=n;++i)
{
int u=i;ans1.clear();
memset(vis,0,sizeof(vis));
while(233)
{
sum=0;int nt=0;vis[u]=true;ans1.push_back(u);
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(vis[v])continue;
if(Ans[v]>Ans[nt])nt=v;
}
if(!nt)break;
u=nt;
}
if(ans1.size()>ans.size())ans=ans1;
if(rand()%20==0)
Ans[i]=ans1.size();
}
printf("%d\n",(int)(ans.size()));
for(int i=0;i<(int)(ans.size());++i)printf("%d\n",ans[i]);
return 0;
}

这样跑完,

\(1,2,5,7,8,9,10\)都是正确的解了

但是因为我这份代码不涉及随机化(尽管我后来加了)

所以答案没有办法更优了

于是直接搜别人的题解。。。

和我一开始的想法比较类似:随机找一棵生成树,求直径

但是我就是真正的随机一棵生成树。。。。

那么如果找生成树呢?

贪心的想,如果能够把树直接拉成一条链,一定更优

一条链有什么特征?

每个点的入度/出度很小

所以,我们按照度数来随机。

大致的过程就是:

首先随机一个点作为根节点

然后检查所有没有被访问过儿子

找到其中出度最小的儿子

然后继续递归处理这个儿子

回溯到这个儿子之后,如果还有儿子没有访问过,直接访问

构建出树之后在上面跑\(bfs\)求直径即可

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 11000
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n,m;
bool vis[MAX];
struct Line{int v,next;}e[MAX<<2];
int h[MAX],cnt=1;
vector<int> ans;
int du[MAX],dg[MAX];
int f[MAX],ret=0,dep[MAX],fa[MAX];
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
void init()
{
memset(h,0,sizeof(h));cnt=1;
memset(f,0,sizeof(f));memset(dep,0,sizeof(dep));
memset(fa,0,sizeof(fa));ret=0;
for(int i=1;i<=n;++i)dg[i]=du[i];
}
int bfs(int S)
{
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(S);
int ret;
while(!Q.empty())
{
int u=Q.front();Q.pop();
ret=u;vis[u]=true;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;
if(vis[v])continue;
vis[v]=true;Q.push(v);
}
}
return ret;
}
vector<int> ans1,ans2;
void jump(int u,int v)
{
ans1.clear();ans2.clear();
if(dep[u]<dep[v])swap(u,v);
while(dep[u]!=dep[v])ans1.push_back(u),u=fa[u];
while(u!=v)
{
ans1.push_back(u);ans2.push_back(v);
u=fa[u];v=fa[v];
}
ans1.push_back(v);
for(int i=ans2.size()-1;i>=0;--i)ans1.push_back(ans2[i]);
if(ans1.size()>ans.size())ans=ans1;
}
vector<int> Ed[MAX];
void Build(int u)
{
vis[u]=true;
for(int i=0;i<Ed[u].size();i++)--dg[Ed[u][i]];
int nt=0;dg[0]=1e9;
for(int i=0;i<Ed[u].size();i++)
{
int v=Ed[u][i];
if(vis[v])continue;
if(dg[nt]>dg[v])nt=v;
else if(dg[nt]==dg[v]&&rand()%2)nt=v;
}
if(nt)Add(u,nt),Add(nt,u),Build(nt);
for(int i=0;i<Ed[u].size();i++)
if(!vis[Ed[u][i]])Add(u,Ed[u][i]),Add(Ed[u][i],u),Build(Ed[u][i]);
}
void dfs(int u,int ff)
{
dep[u]=dep[ff]+1;fa[u]=ff;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)dfs(e[i].v,u);
}
int main()
{
srand(time(NULL));
freopen("guide6.in","r",stdin);
freopen("guide6.out","w",stdout);
n=read();m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
Ed[u].push_back(v);
Ed[v].push_back(u);
du[u]++;du[v]++;
}
int T=1000;
while(T--)
{
init();
int rt=rand()%n+1;
memset(vis,0,sizeof(vis));
Build(rt);
dfs(rt,0);
int u=bfs(rt),v=bfs(u);
jump(u,v);
}
printf("%d\n",(int)(ans.size()));
for(int i=0;i<(int)(ans.size());++i)printf("%d\n",ans[i]);
return 0;
}

提供一下我的答案

戳我下载

【NOI2006】聪明的导游的更多相关文章

  1. 洛谷.4252.[NOI2006]聪明的导游(提答 直径 随机化)

    题目链接 随机化 暴力: 随便从一个点开始DFS,每次从之前得到的f[i]最大的子节点开始DFS.f[i]为从i开始(之前)能得到的最大答案. 要注意的是f[i]应当有机会从更小的答案更新, 9.10 ...

  2. 【洛谷4252】[NOI2006] 聪明的导游(提答题)

    点此看题面 大致题意: 给你一张\(n\)个点.\(m\)条边的无向图,让你找出图上的一条不经过重复节点的最长路(提答+\(spj\)). 随机化乱搞 针对这种提答题,我们就要用随机化乱搞(Cptra ...

  3. [NOI2006] 最大获利

    [NOI2006] 最大获利 ★★★☆   输入文件:profit.in   输出文件:profit.out   简单对比时间限制:2 s   内存限制:512 MB [问题描述] 新的技术正冲击着手 ...

  4. BZOJ1497: [NOI2006]最大获利[最小割 最大闭合子图]

    1497: [NOI2006]最大获利 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 4375  Solved: 2142[Submit][Status] ...

  5. OUC校园导游

    大二专业课太多,都没有好好的在博客上面做笔记,以备后面用的时候可以查找看一下,下面是写的不是完全正确的与图相关的代码~~希望指正~~ /* Name: Copyright: Author:Hxm Da ...

  6. LR12.53—使用HP网络导游示例应用程序

    本教程使用 的HP Web之旅,一个样本的基于Web的旅行社系统,向人们展示LoadRunner将如何作为负载测试解决方案.惠普网络旅游用户连接到Web服务器,搜索航班,预订机票,检查飞行路线. 虽然 ...

  7. 校园导游系统(C++实现,VC6.0编译,使用EasyX图形库)

    运行效果: 说明: 由于当年还不会使用多线程,所以很多获取用户点击的地方都是使用循环实现的...CPU占用率会比较高. 代码: //校园导游系统.cpp 1 #include <graphics ...

  8. BZOJ2429[HAOI2006]聪明的猴子[最小生成树 kruskal]

    2429: [HAOI2006]聪明的猴子 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 896  Solved: 575[Submit][Statu ...

  9. vijos1740 聪明的质监员 (二分、区间求和)

    http://www.rqnoj.cn/problem/657 https://www.vijos.org/p/1740 P1740聪明的质检员 请登录后递交 标签:NOIP提高组2011[显示标签] ...

随机推荐

  1. Vue视图

    1. 基本模板语法 1.1 插值 文本 数据绑定最常见的形式就是使用“Mustache”语法 (双大括号) 的文本插值 v-text 指令也可以用于数据绑定,如果要更新部分的 textContent ...

  2. 查看Linux系统版本的命令

    1.lsb_release -a,即可列出所有版本信息: [root@S-CentOS ~]# lsb_release -a LSB Version: :base-4.0-amd64:base-4.0 ...

  3. PHPCMS的产品筛选功能

    如下图所示功能: 首先,用下面这些代码替换掉phpcms/libs/functions/extention.func.php的内容 <?php /** * extention.func.php ...

  4. dotnet服务器端框架从精通到弃坑

    当你们看到这篇经验分享的时候,我已经把服务器端主要力量转到JAVA了. 纯当留念. 另外里面实现oauth2.0的部分就不写了,因为特殊性太强,完全根据自家需求结合它的理念改写的. 为什么我会选择sp ...

  5. 剑指offer-二维数组中的查找01

    题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 ...

  6. Your funds transfer has been delayed

    Hello from Amazon. Your funds transfer in the amount of 9,422.88 USD has been delayed because the cr ...

  7. 扩展Lucas定理 扩展Lucas板子

    题意概述:多组询问,给出N,K,M,要求回答C(N,K)%M,1<=N<=10^18,1<=K<=N,2<=M<=10^6 分析: 模数不为质数只能用扩展Lucas ...

  8. ionic 开发实例

    ionic 开发实例 一.ionic初始化项目 1:安装ionic npm install -g ionic 2:初始化项目框架 我们可以用命令创建一个应用程序,可以使用我们的一个现成的应用程序模板, ...

  9. gulp配置文件(gulpfile.js)

    需要安装的插件 "gulp": "^3.9.1","gulp-clean": "^0.3.2","gulp-c ...

  10. python 抓取网页(一)

    #-------PYTHON获取网页内容-------------# import sys, urllib url = "http://www.baidu.com" #网页地址 w ...