BZOJ 1556: 墓地秘密【状压DP

80 篇文章 0 订阅
6 篇文章 0 订阅

嗯……就是标准的状压dp,然而…………嗯…………spfa的时候稍微难一些……………………

重点是根本不知道取什么变量名2333333

相当于把每一个关键点的四个方向各设为一个点……以此来转移

grp[i][j]是(i,j)位置是否是墙

dis[i][j][k]是在(i,j)位置,面向k方向,从当前的spfa源点出发,最少多少次转弯可以到达

in_que就是是否在队列里

rec[i][di][j][dj]是从关键点i的di方向上的相邻点(当前状态是刚刚撞了i并停止),到关键点j的dj方向上的相邻点(同样也是刚撞了),需要的最小转弯次数(也就是spfa得到的距离)

f[s][i][di]中,s是状态(撞了哪些点),并且处在关键点i的di方向上的相邻点上



………………啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

反正代码不多也不难写………………………………………………………………………………………………然而…………………………嗯………………………………………………………………………………………………………………………………………………………………………………………………………………



啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

变量名打错了调了一天…………………………我特么………………………………啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊阿啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊阿啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊垃圾游戏毁我青春耗我钱财颓我精神


u和v打反了……我……没看出来…………………………


啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊

不说了……上代码QAQ

#include<bits/stdc++.h>
#define MAXN 102
#define MAXT 15
#define INF 0x3f3f3f3f
using namespace std;	int n,m,t;
const int cx[4]={0,1,0,-1};
const int cy[4]={1,0,-1,0};
int grp[MAXN][MAXN];
int Tx[MAXN],Ty[MAXN];
int sx,sy;

queue<int> que;
int dis[MAXN][MAXN][4];
int in_que[MAXN][MAXN][4];
void spfa(int x,int y,int dir){
	memset(dis,INF,sizeof dis);
	int tmp;
	for(int i=0;i<4;++i)
		dis[x][y][i]=(i!=dir), que.push(x),que.push(y),que.push(i), in_que[x][y][i]=1;
	for(;que.size();){
		x=que.front(),que.pop() , y=que.front(),que.pop() , dir=que.front(),que.pop();
		in_que[x][y][dir]=0;
		for(int i=0;i<4;++i){
			int xx=x+cx[i],yy=y+cy[i];
			if(grp[ xx ][ yy ])
				for(int j=0;j<4;++j)
					if(dis[ xx ][ yy ][j] > ( tmp = dis[x][y][dir] + (j!=i) + (i!=dir) ))
						dis[ xx ][ yy ][j] = in_que[xx][yy][j] ? 
						tmp :  ( que.push(xx) , que.push(yy) , que.push(j) ,
						in_que[ xx ][ yy ][j]=1 , tmp );
		}
	}
}
int rec[MAXT][4][MAXT][4];
int f[1<<MAXT][MAXT][4];

char read_s[MAXN];
int main(){
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=n;++i){
		scanf("%s",read_s+1);
		for(int j=1;j<=m;++j)	grp[i][j]=read_s[j]=='.';
	}
	for(int i=0;i<t;++i)	scanf("%d%d",Tx+i,Ty+i);
	memset(rec,INF,sizeof rec);

	for(int u=0;u<t;++u)
		for(int dir_u=0;dir_u<4;++dir_u){
			int xu=Tx[u]+cx[dir_u],yu=Ty[u]+cy[dir_u];
			if(grp[xu][yu]){
				spfa(xu,yu,dir_u^2);
				for(int v=0;v<t;++v)
					for(int dir_v=0;dir_v<4;++dir_v){
						int xx=Tx[v]+cx[dir_v],yy=Ty[v]+cy[dir_v];
						if(grp[xx][yy])
							rec[u][dir_u][v][dir_v]=dis[xx][yy][dir_v^2];
					}
			}
		}
	scanf("%d%d",&sx,&sy);
	memset(f,INF,sizeof f);
	
	for(int dir_s=0;dir_s<4;++dir_s){
		spfa(sx,sy,dir_s);
		for(int u=0;u<t;++u)
			for(int dir_u=0;dir_u<4;++dir_u){
				int xx=Tx[u]+cx[dir_u],yy=Ty[u]+cy[dir_u];
				if(grp[xx][yy])
					f[1<<u][u][dir_u]=min(f[1<<u][u][dir_u],dis[xx][yy][dir_u^2]+1);
			}
	}
	
	for(int s=1;s<(1<<t);++s)
		for(int u=0;u<t;++u)
			if(s&(1<<u))
				for(int v=0;v<t;++v)
					if(!(s&(1<<v)))
						for(int dir_u=0;dir_u<4;++dir_u)
							for(int dir_v=0;dir_v<4;++dir_v)
								f[s|(1<<v)][v][dir_v]=min(f[s|(1<<v)][v][dir_v], f[s][u][dir_u] + rec[u][dir_u][v][dir_v]);
	int ans=INF;
	
	for(int u=0;u<t;++u)
		for(int dir=0;dir<4;++dir)
			ans=min(ans,f[(1<<t)-1][u][dir]);
	printf("%d",ans<=INF?ans:-1);
	return 0;
}
/*
4 6 3
......
....#.
.....#
....#.
2 5
3 6
4 5
1 5

*/


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值