A.机器人

题目大意:给定一个n*m的地图,有一些障碍物和k个机器人,你每次可以选择一个机器人往任意一个方向推,遇到转向器会转向,两个编号相邻的机器人可以合并,求最少推多少次可以全部合并。

$n,m\leqslant 500 k\leqslant 9$

题解:用f[i][j][k][l]表示i到j的机器人在(k,l)合并的最小次数,那么当(k',l')推一次可以到(k,l)的时候,它可以从f[i][j][k'][l']+1转移。当然,它还可以从f[i][p][k][l]+f[p+1][j][k][l]转移,所以我们先计算出

所有点推一次到哪里,每次做完一个f[i][j]之后,就做一次spfa。

但是spfa会T,并不能过。我们考虑开两个队列,在spfa之前把起始的位置拍好序扔到队列1,然后每次取出两个队列队头较小的松弛,松弛到的点加入队列2,这样可以保证队列1和队列2有序,spfa就进化为了bfs,排序最好用O(n)的计数排序,跑的飞快。

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define INF 32639
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} unsigned short d[][][][];int mark[][][],top=;
int n,h,w,cnt=,L,R;
int v[],sa[];
char st[][];
struct P{short x,y;
P(short x=,short y=):x(x),y(y){}
bool operator !(){return x==&&y==;}
}pos[],to[][][],q[];
bool b[][];
const int dis[][]={{,},{,},{,-},{-,}};
queue<P> q1,q2; P dfs(int x,int y,int dir)
{
if(mark[x][y][dir]==cnt) return to[x][y][dir]=P(-,-);mark[x][y][dir]=cnt;
if(!(!to[x][y][dir])) return to[x][y][dir];
int pre=dir;
if(st[x][y]=='A') dir=(dir+)%;
if(st[x][y]=='C') dir=(dir+)%;
int xx=x+dis[dir][],yy=y+dis[dir][];
if(xx<||yy<||xx>h||yy>w||st[xx][yy]=='x') return to[x][y][pre]=P(x,y);
return to[x][y][pre]=dfs(xx,yy,dir);
} void spfa()
{
memset(v,,sizeof(v));
for(int i=;i<=top;i++)v[d[L][R][q[i].x][q[i].y]]++;
for(int i=;i<=INF;i++)v[i]+=v[i-];
for(int i=;i<=top;i++) sa[v[d[L][R][q[i].x][q[i].y]]--]=i;
for(int i=;i<=top;i++) q1.push(q[sa[i]]);
top=;
while((!q1.empty())||(!q2.empty()))
{
P now;
if(q1.empty()||((!q2.empty())&&d[L][R][q1.front().x][q1.front().y]>d[L][R][q2.front().x][q2.front().y]))
now=q2.front(),q2.pop();
else
now=q1.front(),q1.pop();
b[now.x][now.y]=;
for(int i=;i<;i++)
{
P t=to[now.x][now.y][i];
if(t.x==-||t.y==-) continue;
if(d[L][R][now.x][now.y]+<d[L][R][t.x][t.y])
{
d[L][R][t.x][t.y]=d[L][R][now.x][now.y]+;
if(!b[t.x][t.y])
{
b[t.x][t.y]=;
q2.push(t);
}
}
} }
} int main()
{
n=read();w=read();h=read();
memset(d,,sizeof(d));
for(int i=;i<=h;i++)
{
scanf("%s",st[i]+);
for(int j=;j<=w;j++)
if(st[i][j]>''&&st[i][j]<='')
pos[st[i][j]-'']=P(i,j);
}
for(int i=;i<=h;i++)
for(int j=;j<=w;j++)
if(st[i][j]!='x')
for(int k=;k<;k++)
++cnt,dfs(i,j,k);
for(int i=;i<=n;i++)
{
b[pos[i].x][pos[i].y]=;q[++top]=pos[i];
L=R=i;d[i][i][pos[i].x][pos[i].y]=;spfa();
}
for(int l=,j;l<=n;l++)
for(int i=;(j=i+l-)<=n;i++)
{
for(int x=;x<=h;x++)
for(int y=;y<=w;y++)
{
for(int k=i;k<j;k++)
d[i][j][x][y]=min(d[i][j][x][y],(unsigned short)(d[i][k][x][y]+d[k+][j][x][y]));
if(d[i][j][x][y]<INF)
q[++top]=P(x,y),b[x][y]=;
}
L=i;R=j;spfa();
}
unsigned short ans=;
for(int i=;i<=h;i++)
for(int j=;j<=w;j++)
ans=min(ans,d[][n][i][j]);
if(ans<) printf("%u\n",ans);
else puts("-1");
return ;
}

B.[Apio2013]道路费用

$n\leqslant 10^{5},m\leqslant 3*10^{5},k\leqslant 20$

题解:强制选这K条边,然后我们发现K条边把整个图割成了K+1块,每一块内选的边肯定是相同的。我们把这几块缩点,然后枚举每条边选不选,对每种情况,暴力算出每条边的最大长度,通过dp算出这种情况的答案就可以啦。

复杂度$mlogm+k^{2}*2^{k}$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define INF 200000000000000000LL
#define MN 100000
#define MM 300000
#define MK 20
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} struct edge{
int from,to;ll w;int kind;
}e[MM+MK+],ek[MK+],e3[MK+];
struct nedge{int to,next,kind;}e2[MN*+];
ll ans=,sum[MK+],p[MN+],val[MK+],mn[MK+];
int n,m,K,cnt=,s[MN+],head[MN+],cn=,bel[MN+],dep[MK+],fa2[MK+];
bool mark[MN+],b[MK+]; bool cmp(edge x,edge y){return x.w<y.w||(x.w==y.w&&x.kind>y.kind);}
int find(int x)
{
return !s[x]?x:s[x]=find(s[x]);
} void ins(int f,int t,int kind=)
{
e2[++cnt]=(nedge){t,head[f],kind};head[f]=cnt;
e2[++cnt]=(nedge){f,head[t],kind};head[t]=cnt;
} void kruscal()
{
for(int i=;i<=K;i++)
{
int x=find(ek[i].from),y=find(ek[i].to);
s[x]=y,ins(ek[i].from,ek[i].to,);
}
for(int i=;i<=m;i++)
{
int x=find(e[i].from),y=find(e[i].to);
if(x!=y)s[x]=y,ins(e[i].from,e[i].to,);
}
} void getv(int x)
{
mark[x]=;bel[x]=cn;val[cn]+=p[x];
for(int i=head[x];i;i=e2[i].next)
if(!mark[e2[i].to]&&!e2[i].kind)
getv(e2[i].to);
} void dp(int x,int fa)
{
sum[x]=val[x];fa2[x]=fa;
for(int i=head[x];i;i=e2[i].next)
if(e2[i].to!=fa)
{
dep[e2[i].to]=dep[x]+;
dp(e2[i].to,x);sum[x]+=sum[e2[i].to];
}
}
int tms=;
void solve()
{
ll tot=;cnt=;
for(int i=;i<=cn;i++)s[i]=,head[i]=,mn[i]=INF;
for(int i=;i<=K;i++)
if(b[i])
{
int x=find(ek[i].from),y=find(ek[i].to);
if(x==y)return;s[x]=y;ins(ek[i].from,ek[i].to);
}
tms++;
for(int i=;i<=K;i++)
{
int x=find(e3[i].from),y=find(e3[i].to);
if(x!=y) s[x]=y,ins(e3[i].from,e3[i].to);
}
dp(,);
for(int i=;i<=K;i++)
{
int u=e3[i].from,v=e3[i].to;
if(dep[u]<dep[v]) swap(u,v);
while(dep[u]>dep[v]) mn[u]=min(mn[u],e3[i].w),u=fa2[u];
while(u!=v)
{
mn[u]=min(mn[u],e3[i].w);
mn[v]=min(mn[v],e3[i].w);
u=fa2[u],v=fa2[v];
}
}
for(int i=;i<=K;i++) if(b[i])
{
int u=ek[i].from,v=ek[i].to;
if(dep[u]<dep[v]) swap(u,v);
tot+=1LL*mn[u]*sum[u];
}
ans=max(ans,tot);
} void dfs(int x)
{
if(x>K)
{
solve();
return;
}
b[x]=;dfs(x+);
b[x]=;dfs(x+);
} int main()
{
n=read();m=read();K=read();
for(int i=;i<=m;i++)
e[i].from=read(),e[i].to=read(),e[i].w=read();
for(int i=;i<=K;i++)
ek[i].from=read(),ek[i].to=read();
for(int i=;i<=n;i++)p[i]=read();
sort(e+,e+m+,cmp);kruscal();
for(int i=;i<=n;i++)if(!mark[i]) ++cn,getv(i);
cnt=;
for(int i=;i<=cn;i++) s[i]=;
for(int i=;i<=m+K;i++) if(!e[i].kind)
{
int x=bel[e[i].from],y=bel[e[i].to],f1=find(x),f2=find(y);
if(f1!=f2) s[f1]=f2,e3[++cnt]=(edge){x,y,e[i].w,};
}
for(int i=;i<=K;i++) ek[i].from=bel[ek[i].from],ek[i].to=bel[ek[i].to];
dfs();
cout<<ans;
return ;
}

[APIO2013]的更多相关文章

  1. 【BZOJ】【3205】【APIO2013】机器人robot

    斯坦纳树 好神啊……Orz zyf && PoPoQQQ 为啥跟斯坦纳树扯上关系了?我想是因为每个点(robot)都沿着树边汇到根的时候就全部合起来了吧= =这个好像和裸的斯坦纳树不太 ...

  2. bzoj3205 [Apio2013]机器人

    3205: [Apio2013]机器人 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 953  Solved: 227[Submit][Status] ...

  3. [BZOJ3206][APIO2013]道路费用(最小生成树)

    3206: [Apio2013]道路费用 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 568  Solved: 266[Submit][Status ...

  4. [BZOJ3205][APIO2013]Robot(斯坦纳树)

    3205: [Apio2013]机器人 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 1007  Solved: 240[Submit][Status ...

  5. [Bzoj3206][Apio2013]道路费用(kruscal)(缩点)

    3206: [Apio2013]道路费用 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 536  Solved: 252[Submit][Status ...

  6. [Bzoj3205][Apio2013]机器人(斯坦纳树)(bfs)

    3205: [Apio2013]机器人 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 977  Solved: 230[Submit][Status] ...

  7. APIO2013 tasksauthor

    喜闻乐见的提答题,这道题还是蛮有趣的 数据结构题写得心塞,来一道提答意思意思 如果喜欢这类题的话还可以去做做uoj83. 这题是给出了两个问题,一个最短路,一个无向图染色问题. Data 1 Floy ...

  8. BZOJ3206 [Apio2013]道路费用

    首先我们强制要求几条待定价的边在MST中,建出MST 我们发现这个MST中原来的边是一定要被选上的,所以可以把点缩起来,搞成一棵只有$K$个点的树 然后$2^K$枚举每条边在不在最终的MST中,让在最 ...

  9. UOJ #109「APIO2013」TASKSAUTHOR

    貌似是最入门的题答题 刚好我就是入门选手 就这样吧 UOJ #109 题意 太热了不讲了 $ Solution$ 第一个点:$ 105$个数字卡掉$ Floyd$ 直接$101$个点无出边一次询问就好 ...

随机推荐

  1. js数组string对象api常用方法

    charAt() 方法可返回指定位置的字符. stringObject.charAt(index) indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置. stringObject ...

  2. js 防止重复点击

    1.添加flag 适用于ajax 表单提交,提交之前flag = false , 提及中,true ,提交后false 2.事件重复点击: <script> var throttle = ...

  3. 你能选择出,前几个元素吗?使用纯css

    面试被问到 ,你能选择出前几个元素吗?括弧只能使用css 我当时是一脸懵逼... 回去的路上思考一路 终于想到了解决办法 虽然为时已晚 但是觉得很有意义... 首先要用到 否定选择器 : :not() ...

  4. spring MVC中定义异常页面

    如果我们在使用Spring MVC的过程中,想自定义异常页面的话,我们可以使用DispatcherServlet来指定异常页面,具体的做法很简单: 下面看我曾经的一个项目的spring配置文件: 1 ...

  5. python基础-循环

    循环 循环 要计算1+2+3,我们可以直接写表达式: >>> 1 + 2 + 3 6 要计算1+2+3+...+10,勉强也能写出来. 但是,要计算1+2+3+...+10000,直 ...

  6. Help Jimmy ~poj-1661 基础DP

    Help Jimmy" 是在下图所示的场景上完成的游戏. 场景中包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无限. Jimmy老鼠在时刻0从高于所有平台的某处开始下落, ...

  7. 移动端,input输入框被手机输入法解决方案

    当界面元素靠下时候的时候,input输入框会被系统的键盘遮挡. 我们可以让界面向上移动一定距离去避免遮挡. $('#money').click(function(){ setTimeout(funct ...

  8. Struts(十一):OGNL表达式(二)

    Map栈 :request,session,application的一个属性值或一个请求参数的值. 若想访问ContextMap里的某个对象的属性,可以使用以下几种之一: #object.proper ...

  9. 一、WINDOWS下 RabbitMQ安装部署

    安装需要用管理员权限,全部右键管理员身份运行.建议安装到虚拟机里面,免得影响日常使用. 1.下载   https://dl.bintray.com/rabbitmq/all/rabbitmq-serv ...

  10. JS查找字符串中出现次数最多的字符

    本文给大家带来两种js中查找字符串中出现次数最多的字符,在这两种方法中小编推荐使用第二种,对js查找字符串出现次数的相关知识感兴趣的朋友一起看看吧   在一个字符串中,如 'zhaochucichuz ...