题解:B3791 [信息与未来 2023] 电路布线
解 1:爆搜+剪枝
暴力搜索很明显是枚举每一个为 . 的点保留原来的状态或者变为 +,最后进行判断。时间复杂度
考虑剪枝优化。如果当前的答案之后就算加上了理论的全部可以为 + 的地方还是比不过原来的答案,那么就可以直接返回。
这个很像 IDA-star 中的估价函数,只不过这里的最大深度是搜过的答案。
IDA-star 是用于应对最小答案,方法是将答案估小。而这里要求的是最答案,所以应当将答案估大。比如当前答案为
这里可以估成之后所有点都为 + 的情况,一定不会 WA。
判断是否形成环也很好弄,并查集、dfs 或者 bfs 都是可以的。这里用了 dfs(带权并查集之前写挂了,现在还在痛恨并查集。),比如走着走着走到了之前标记的点,并且不是上一个点,那就有环。
发现这里的估价函数剪枝可能优化不了时间(原理同 K 短路的 A-star 算法被卡),还需要加上一些剪枝。
比如当前节点加上去就已经是有环的了,那么就不用往后搜。这个限制了指数(虽然本人很蒻算不出最少能卡多少个不对的情况),而且 dfs 判环最多
加上去就能够 AC 了。
#include<bits/stdc++.h>
#define MAXN 17
using namespace std;
int n,m,sx,sy,cnt,ans;
char mp[MAXN][MAXN];
char ouf[MAXN][MAXN];
char dfn[MAXN][MAXN];
bool vis[MAXN][MAXN];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
inline int goal(const int &x,const int &y){
return n*m-(x-1)*m-y;
}
bool check(const int &x,const int &y,const int &px,const int &py){
if(vis[x][y]){
return false;
}
vis[x][y]=true;
--cnt;
for(register int i=0;i<4;++i){
const int nx=x+dx[i];
const int ny=y+dy[i];
if(px==nx&&py==ny){
continue;
}
if(1<=nx&&nx<=n&&1<=ny&&ny<=m&&mp[nx][ny]=='+'){
if(!check(nx,ny,x,y)){
return false;
}
}
}
return true;
}
void dfs(int x,int y,const int &sum){
if(y==m+1){
++x;
y=1;
}
if(sum+goal(x,y)<=ans){
return;
}
if(x==n+1){
memset(vis,0,sizeof(vis));
cnt=sum;
if(check(sx,sy,-1,-1)&&!cnt){
memcpy(ouf,mp,sizeof(mp));
ans=sum;
}
return;
}
if(mp[x][y]=='.'){
mp[x][y]='+';
memset(vis,0,sizeof(vis));
if(check(x,y,-1,-1)){
dfs(x,y+1,sum+1);
}
mp[x][y]='.';
}
dfs(x,y+1,sum);
}
int main(){
register int sum=0;
scanf("%d %d",&n,&m);
for(register int i=1;i<=n;++i){
scanf("%s",mp[i]+1);
for(register int j=1;j<=m;++j){
if(mp[i][j]=='+'){
++sum;
sx=i;
sy=j;
}
ouf[i][j]=mp[i][j];
}
}
dfs(1,1,sum);
for(register int i=1;i<=n;++i){
for(register int j=1;j<=m;++j){
putchar(ouf[i][j]);
}
putchar('\n');
}
return 0;
}
解 2:折半搜索
还是原来的复杂度:
原理是把上半部分搜一遍,把下半部分搜一遍,时间复杂度
但是具体怎么用折半搜索实现呢?Luogu 上目前没有,我从官方题解上找出了一个方法(本蒻蒻抛弃的自认为难写方法)。
枚举中转点,即在
但是,本人后面发现折半搜索各种写法的正确性问题:
- 如果枚举上下最优,那么有可能上面最优下面最优,连起来并不合法。
- 如果枚举上面最优,下面按照上面的网格图进行正确性剪枝,那么连起来可能并不最优。
这里,作者还是希望有人能够评论给出一种正确折半的思路的,谢谢各位观看!
我是错解。