记录编号 93339 评测结果 AAAAAAAAAA
题目名称 [WC 1999]迷宫改造 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.018 s
提交时间 2014-03-25 20:10:29 内存使用 0.98 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int SIZEn=30,SIZEN=10800+10,INF=0x7fffffff/2;
//本题下标从0开始
int n,m,K;//N行M列K个墙
bool around[SIZEn][SIZEn][5]={0};
//上下左右分别是0123
//x行y列
int srcx[5]={0},srcy[5]={0},desx[5]={0},desy[5]={0};//三个人的起点和终点
int P;
int dx[5]={-1,1,0,0},dy[5]={0,0,-1,1};
void SPFA(vector<pair<int,int> > c[SIZEN],int N,int S,int f[SIZEN]){//图中顶点0~N-1,邻接表为c,以S出发,结果存于f
	queue<int> Q;
	bool inq[SIZEN]={0};
	for(int i=0;i<N;i++) f[i]=INF;
	f[S]=0,inq[S]=true,Q.push(S);
	while(!Q.empty()){
		int x=Q.front();Q.pop();inq[x]=false;
		for(int i=0;i<c[x].size();i++){
			int u=c[x][i].first;
			if(f[x]+c[x][i].second<f[u]){
				f[u]=f[x]+c[x][i].second;
				if(!inq[u]){
					inq[u]=true;
					Q.push(u);
				}
			}
		}
	}
}
vector<pair<int,int> > monose[SIZEN],mononw[SIZEN];//单层图,只向东南和只向西北
vector<pair<int,int> > layer[SIZEN];//分层图
int distsrc[3][SIZEN]={0},distdes[3][SIZEN]={0};//从每个人起点,终点出发的最短路
int bypasslen[3]={0};//自己单独走的长度
void printstate(int s){//调试接口,输出点代表的状态
	int y=s%m;s/=m;
	int x=s%n;s/=n;
	int e2=s%3;s/=3;
	int e1=s%3;s/=3;
	int e0=s;
	cout<<"("<<e0<<e1<<e2<<" "<<x<<" "<<y<<")";
}
int hash(int e0,int e1,int e2,int x,int y){
	int s=e0*9+e1*3+e2;
	return (s*n+x)*m+y;
}
int hash(int x,int y){return x*m+y;}//不考虑进出状态的hash
void makeartery(int e0,int e1,int e2){//建立分层图
	//这函数太TM丑了!!!!!!!!!
	for(int i=0;i<27*m*n;i++) layer[i].clear();
	for(int et0=0;et0<=e0*2;et0++){
		for(int et1=0;et1<=e1*2;et1++){
			for(int et2=0;et2<=e2*2;et2++){
				for(int i=0;i<n;i++){
					for(int j=0;j<m;j++){
						for(int d=1;d<=3;d+=2){
							int nx=i+dx[d],ny=j+dy[d];
							if(nx<0||nx>n-1||ny<0||ny>m-1) continue;
							int w;
							if(et0==1||et1==1||et2==1) w=around[i][j][d];//如果有人在干路上那么计入权值
							else w=0;//否则不计入
							layer[hash(et0,et1,et2,i,j)].push_back(make_pair(hash(et0,et1,et2,nx,ny),w));//这是基本图
						}
					}
				}
			}
		}
	}
	int s1,s2;
	if(e0){//它存在进入/离开的可能性
		for(int et1=0;et1<=e1*2;et1++){
			for(int et2=0;et2<=e2*2;et2++){
				for(int i=0;i<n;i++){
					for(int j=0;j<m;j++){
						s1=hash(0,et1,et2,i,j),s2=hash(1,et1,et2,i,j);
						layer[s1].push_back(make_pair(s2,distsrc[0][hash(i,j)]));//进入干道
						s1=hash(1,et1,et2,i,j),s2=hash(2,et1,et2,i,j);
						layer[s1].push_back(make_pair(s2,distdes[0][hash(i,j)]));//离开干道
					}
				}
			}
		}
	}
	if(e1){
		for(int et0=0;et0<=e0*2;et0++){
			for(int et2=0;et2<=e2*2;et2++){
				for(int i=0;i<n;i++){
					for(int j=0;j<m;j++){
						s1=hash(et0,0,et2,i,j),s2=hash(et0,1,et2,i,j);
						layer[s1].push_back(make_pair(s2,distsrc[1][hash(i,j)]));
						s1=hash(et0,1,et2,i,j),s2=hash(et0,2,et2,i,j);
						layer[s1].push_back(make_pair(s2,distdes[1][hash(i,j)]));
					}
				}
			}
		}
	}
	if(e2){
		for(int et0=0;et0<=e0*2;et0++){
			for(int et1=0;et1<=e1*2;et1++){
				for(int i=0;i<n;i++){
					for(int j=0;j<m;j++){
						s1=hash(et0,et1,0,i,j),s2=hash(et0,et1,1,i,j);
						layer[s1].push_back(make_pair(s2,distsrc[2][hash(i,j)]));
						s1=hash(et0,et1,1,i,j),s2=hash(et0,et1,2,i,j);
						layer[s1].push_back(make_pair(s2,distdes[2][hash(i,j)]));
					}
				}
			}
		}
	}
}
int f[SIZEN]={0};
int test(int e0,int e1,int e2){
	makeartery(e0,e1,e2);
	int ans;
	SPFA(layer,27*m*n,0,f);
	ans=f[hash(e0*2,e1*2,e2*2,n-1,m-1)];
	if(!e0) ans+=bypasslen[0];
	if(!e1) ans+=bypasslen[1];
	if(!e2) ans+=bypasslen[2];
	return ans;
}
void work(void){
	int ans=INF;
	for(int i=0;i<=1;i++){
		for(int j=0;j<=1;j++){
			for(int k=0;k<=1;k++) ans=min(ans,test(i,j,k));
		}
	}
	printf("%d\n",ans);
}
void getbypass(void){
	for(int i=0;i<3;i++) SPFA(monose,n*m,hash(srcx[i],srcy[i]),distsrc[i]);
	for(int i=0;i<3;i++) SPFA(mononw,n*m,hash(desx[i],desy[i]),distdes[i]);
	for(int i=0;i<3;i++) bypasslen[i]=distsrc[i][hash(desx[i],desy[i])];
}
void makemonograph(void){
	int s1,s2;
	for(int i=0;i<n;i++){//东和南
		for(int j=0;j<m;j++){
			s1=hash(i,j);
			for(int d=1;d<=3;d+=2){
				int nx=i+dx[d],ny=j+dy[d];
				if(nx<0||nx>n-1||ny<0||ny>m-1) continue;
				s2=hash(nx,ny);
				monose[s1].push_back(make_pair(s2,around[i][j][d]));
			}
		}
	}
	for(int i=0;i<n;i++){//西和北
		for(int j=0;j<m;j++){
			s1=hash(i,j);
			for(int d=0;d<=2;d+=2){
				int nx=i+dx[d],ny=j+dy[d];
				if(nx<0||nx>n-1||ny<0||ny>m-1) continue;
				s2=hash(nx,ny);
				mononw[s1].push_back(make_pair(s2,around[i][j][d]));
			}
		}
	}
}
int checkdir(int x1,int y1,int x2,int y2){//2在1的什么方位
	if(x2<x1) return 0;
	if(x2>x1) return 1;	
	if(y2<y1) return 2;
	if(y2>y1) return 3;
	return -1;
}
void read(void){
	scanf("%d%d%d",&n,&m,&K);
	int x1,y1,x2,y2;
	memset(around,1,sizeof(around));
	for(int i=0;i<K;i++){
		scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
		x1--,y1--,x2--,y2--;
		around[x1][y1][checkdir(x1,y1,x2,y2)]=0;
		around[x2][y2][checkdir(x2,y2,x1,y1)]=0;
	}
	for(int i=0;i<m;i++) around[0][i][0]=1,around[n-1][i][1]=1;
	for(int i=0;i<n;i++) around[i][0][2]=1,around[i][m-1][3]=1;//四周围一圈
	scanf("%d",&P);
	for(int i=0;i<P;i++) scanf("%d%d%d%d",&srcx[i],&srcy[i],&desx[i],&desy[i]),srcx[i]--,srcy[i]--,desx[i]--,desy[i]--;
	for(int i=P;i<3;i++) srcx[i]=srcx[P-1],srcy[i]=srcy[P-1],desx[i]=desx[P-1],desy[i]=desy[P-1];
	P=3;
}
int main(){
	freopen("rebuildmaze.in","r",stdin);
	freopen("rebuildmaze.out","w",stdout);
	read();
	makemonograph();
	getbypass();
	work();
	return 0;
}