Baltic Olympiad in Informatics 2016
Bosses | Park | Spiral | Cities | Maze | Swap |
---|---|---|---|---|---|
链接 题面链接 中文题面
A. Bosses
可以发现一个方案的总代价是所有点的深度之和。考虑枚举根,贪心的选一定让每个点往深度最小的点上挂。
所以连反边 bfs 一遍即可。复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define N 5010
#define ll long long
using namespace std;
int dis[N],n;
vector<int>g[N];
ll ans=-1;
void bfs(int s)
{
for(int i=1;i<=n;i++) dis[i]=0;
dis[s]=1;queue<int>q;q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int v:g[u]) if(!dis[v]) dis[v]=dis[u]+1,q.push(v);
}
for(int i=1;i<=n;i++) if(!dis[i]) return;
ll res=0;
for(int i=1;i<=n;i++) res+=dis[i];
if(ans==-1 || ans>res) ans=res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int k,x;scanf("%d",&k);
while(k --> 0) scanf("%d",&x),g[x].push_back(i);
}
for(int i=1;i<=n;i++) bfs(i);
printf("%lld\n",ans);
return 0;
}
B. Park
定义两个圆之间的边为它们的距离(圆心距离减去半径之和)认为四个边界是四个特殊的圆。那么要使 不连通,需要存在从 的边界到其他边界只通过 的边的路径。换句话说就是把 割开了。
其他同理。可以发现这就是最小瓶颈路,直接暴力枚举每对边界,暴力求瓶颈路,就可以做到 查询。
复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 2010
#define db double
#define inf 1e18
#define eps 1e-9
using namespace std;
int X,Y;
struct node{
int x,y;
node(int x=0,int y=0):x(x),y(y){}
node operator +(node a){return node(x+a.x,y+a.y);}
node operator -(node a){return node(x-a.x,y-a.y);}
}p[N];int r[N];
db dis(node a){return sqrt(1ll*a.x*a.x+1ll*a.y*a.y);}
db dis(int x,int y){return dis(p[x]-p[y])-r[x]-r[y];}
/*
4
---
| |
1 | | 3
| |
---
2
*/
db dis_edge(int a,int op)
{
if(op==1) return p[a].x-r[a];
if(op==2) return p[a].y-r[a];
if(op==3) return X-p[a].x-r[a];
if(op==4) return Y-p[a].y-r[a];
return inf;
}
int f[N],n;
int find(int x){return x==f[x]?f[x]:(f[x]=find(f[x]));}
struct road{
int x,y;db w;
}e[N*N];int et;
db get_dis(int r1,int r2)
{
for(int i=1;i<=n+4;i++) f[i]=i;
for(int i=1;i<=et;i++)
{
int x=find(e[i].x),y=find(e[i].y);
if(x!=y) f[x]=y;
if(find(r1)==find(r2)) return e[i].w;
}
return inf;
}
db w[5][5],q[5][5];
int main()
{
int m;scanf("%d%d%d%d",&n,&m,&X,&Y);
for(int i=1;i<=n;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&r[i]);
for(int j=1;j<=4;j++)
for(int i=1;i<=n;i++) e[++et]={i,j+n,dis_edge(i,j)};
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) e[++et]={i,j,dis(i,j)};
sort(e+1,e+et+1,[&](road a,road b){return a.w<b.w;});
for(int i=1;i<=4;i++)
for(int j=i+1;j<=4;j++) w[i][j]=w[j][i]=get_dis(n+i,n+j);
// for(int i=1;i<=4;i++,puts(""))
// for(int j=1;j<=4;j++) printf("%.6lf ",w[i][j]);
/*
4-4-3
| |
1 3
| |
1-2-2
*/
q[1][2]=q[2][1]=min({w[2][4],w[2][3],w[2][1]});
q[2][3]=q[3][2]=min({w[3][4],w[3][1],w[3][2]});
q[3][4]=q[4][3]=min({w[4][1],w[4][2],w[4][3]});
q[4][1]=q[1][4]=min({w[1][2],w[1][3],w[1][4]});
q[1][3]=q[3][1]=min({w[1][3],w[2][4],w[1][2],w[3][4]});
q[2][4]=q[4][2]=min({w[1][3],w[2][4],w[1][4],w[2][3]});
// for(int i=1;i<=4;i++,puts(""))
// for(int j=1;j<=4;j++) printf("%.6lf ",q[i][j]);
for(int i=1;i<=4;i++) q[i][i]=inf;
while(m --> 0)
{
int r,e;scanf("%d%d",&r,&e);
for(int i=1;i<=4;i++) if(q[i][e]+eps>=r*2) printf("%d",i);
puts("");
}
return 0;
}
D. Cities
最小斯坦纳树板子题。
用 dijkstra 增广,复杂度 。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#define ll long long
#define N 100010
#define inf 100000000000000000
#pragma GCC optimize(3)
using namespace std;
typedef pair<ll,int> P;
priority_queue<P,vector<P>,greater<P>>q;
bool vis[N];int n;
int nxt[N<<2],to[N<<2],w[N<<2],head[N],cnt;
void add(int u,int v,int w0)
{
nxt[++cnt]=head[u];to[cnt]=v;
w[cnt]=w0;head[u]=cnt;
}
void dij(ll f[])
{
for(int i=1;i<=n;i++) vis[i]=false;
while(!q.empty())
{
int u=q.top().second;q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=head[u];i;i=nxt[i])
if(f[to[i]]>f[u]+w[i]) f[to[i]]=f[u]+w[i],q.emplace(f[to[i]],to[i]);
}
}
ll f[33][N];
int main()
{
memset(f,0x3f,sizeof(f));
int m,k;scanf("%d%d%d",&n,&k,&m);
for(int i=0,x;i<k;i++) scanf("%d",&x),f[1<<i][x]=0;
for(int i=1,u,v,w;i<=m;i++) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
for(int s=1;s<1<<k;s++)
{
for(int u=1;u<=n;u++)
for(int t=(s-1)&s;t;t=(t-1)&s) f[s][u]=min(f[s][u],f[t][u]+f[s^t][u]);
for(int u=1;u<=n;u++) if(f[s][u]<=inf) q.emplace(f[s][u],u);
dij(f[s]);
}
printf("%lld\n",*min_element(f[(1<<k)-1]+1,f[(1<<k)-1]+n));
return 0;
}
F. Swap
题目给的序列可以看成一棵完全二叉树,其中一个节点可以依次和左右儿子交换。
不妨假设根,左儿子,右儿子分别是 。
- ,显然什么都不干。
- ,必然只能交换 。
- ,根必然是 ,左右儿子可以是 也可以是 。
问题在于 优还是 更优不能直接判断。
不妨假设 ,如果 放到左子树后最后的位置是 ,那么 放到左子树后 位置的值一定会变大。右子树同理。所以只需要看 放到左子树后的位置与放到右子树的位置哪一个靠前即可。
所以假设 被放入左子树,利用类似的策略可以确定 最终位置。于是就可以推出 被放入左子树优还是右子树优。
考虑分析时间复杂度:注意到一个事情,就是假设 放入 时,必然有 是 的祖先或者祖先的兄弟,换句话说合法 取值只有 个。直接用 map
记忆化搜索,这样一个点只会被访问 次。
总复杂度 ,并且跑不太满。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define N 400010
using namespace std;
int p[N],n;
map<pair<int,int>,int>mp;
int find(int u,int v)//if p_u becomes v
{
if(u>n) return 0;
if(mp.count({u,v})) return mp[{u,v}];
int &b=p[u<<1],&c=p[u<<1|1],&w=mp[{u,v}];
if(v<min(b,c)) return w=0;
if(b<c) return w=find(u<<1,v)+1;
else if(b<v)
{
if(find(u<<1,b)>find(u<<1|1,b)) return w=find(u<<1,v)+1;
else return w=find(u<<1|1,v)+1;
}
else return w=min(find(u<<1,v),find(u<<1|1,v))+1;
}
void solve(int u)
{
if(u>n) return;
int &a=p[u],&b=p[u<<1],&c=p[u<<1|1];
if(a<min(b,c)){solve(u<<1);solve(u<<1|1);return;}
if(b<c){swap(a,b);solve(u<<1);solve(u<<1|1);return;}
// printf("%d %d: %d, ",u<<1,min(a,b),find(u<<1,min(a,b)));
// printf("%d %d: %d\n",u<<1|1,min(a,b),find(u<<1|1,min(a,b)));
swap(a,c);if(b>c) swap(b,c);
if(find(u<<1,b)>find(u<<1|1,b)) swap(b,c);
solve(u<<1);solve(u<<1|1);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=n+1;i<=n*2+1;i++) p[i]=n+1;
solve(1);
for(int i=1;i<=n;i++) printf("%d ",p[i]);
return 0;
}
本文来自博客园,作者:Flying2018,转载请注明原文链接:https://www.cnblogs.com/Flying2018/p/BOI2016.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理