tozangezan's diary

勝手にソースコードをコピペして利用しないでください。

AOJ 2319: ソウルジェムゲーム

前半パートは解説参照。
多項式でできます。
dp[i][j][k][l][m]: i段目、Sがj列、Kがk列にいる。1個前のときSはl列に居た。満たすべき条件二つはmで管理。

場合わけが多すぎてかなり大変。

#include<stdio.h>
#include<algorithm>
using namespace std;
char str[12][12];
int dp[12][12][12][12][4];
int H,W;
int sr,sc,kr,kc,SR,SC,KR,KC;
inline int ABS(int a){return max(a,-a);}
inline void upd(int a,int b,int c,int d,int e){
	if(a>=sr){
		if(a>=kr)return;
		if(a+1<KR)dp[a+1][11][11][b][e|2]=min(dp[a+1][11][11][b][e|2],dp[a][b][c][d][e]);
		else if(a+1==KR)dp[a+1][11][KC][b][e|2]=min(dp[a+1][11][KC][b][e|2],dp[a][b][c][d][e]);
		else{
			for(int y=0;y<W;y++){
				bool d2=false;
				for(int z=min(y,c);z<=max(y,c);z++)if(str[a][z]=='#')d2=true;
				if(str[a+1][y]=='#')d2=true;
				if(a+1==kr&&kc!=y)d2=true;
				if(d2)continue;
				int x=b;
				int ks=0;
				int vt=0;
				for(int z=min(y,c);z<max(y,c);z++){
					bool iL=(min(b,x)<=z)&&(z<=max(b,x));
					bool iR=(min(b,x)<=z+1)&&(z+1<=max(b,x));
					if(!iL&&!iR)ks++;
					else if(!(iL&&iR)){
						if(!vt&&a==SR&&(z==SC||z+1==SC)){vt=1;ks++;}
					//	else if(!vt&&a==sr&&(z==sc||z+1==sc)){vt=1;ks++;}
						else ks+=2;
					}
				}
				if(d!=11&&a>KR&&a<=sr&&min(b,d)<=c&&c<=max(b,d)&&min(b,x)<=c&&c<=max(b,x)){
					if(a-1==SR&&c==SC)ks--;
					else if(a-1==sr&&c==sc)ks--;
					else ks-=2;
				}
				if((SR!=a||y!=SC)&&min(b,x)<=y&&y<=max(b,x))ks+=2;
				else ks++;
				if(d!=11&&a>KR&&a<=sr&&min(b,x)<=c&&c<=max(b,x)&&!(min(b,d)<=c&&c<=max(b,d)))ks++;
				int te=e;
				if(c<min(b,x)||max(b,x)<c)te|=2;
				if(b<min(c,y)||max(c,y)<b)te|=1;
				dp[a+1][11][y][b][te]=min(dp[a+1][11][y][b][te],dp[a][b][c][d][e]+ks);
			}
		}
		return;
	}
	for(int x=0;x<W;x++){
		bool d1=false;
		for(int z=min(x,b);z<=max(x,b);z++)if(str[a][z]=='#')d1=true;
		if(str[a+1][x]=='#')d1=true;
		if(a+1==sr&&sc!=x)d1=true;
		
		if(d1)continue;
		if(a<KR){
			int ks=ABS(x-b)+1;
			if(a+1==KR)dp[a+1][x][KC][b][e|1]=min(dp[a+1][x][KC][b][e|1],dp[a][b][c][d][e]+ks);
			else dp[a+1][x][11][b][e|1]=min(dp[a+1][x][11][b][e|1],dp[a][b][c][d][e]+ks);
			continue;
		}
		if(a>=kr){
			int ks=ABS(x-b)+1;
			if(a==kr&&min(b,x)<=c&&c<=max(b,x))ks++;
			if(d!=11&&a>KR&&min(b,d)<=c&&c<=max(b,d)&&min(b,x)<=c&&c<=max(b,x)){
				if(a-1==SR&&c==SC)ks--;
				else if(a-1==sr&&c==sc)ks--;
				else ks-=2;
			}
			if(d!=11&&a>KR&&min(b,x)<=c&&c<=max(b,x)&&!(min(b,d)<=c&&c<=max(b,d)))ks++;
			int te=e|1;
			if(a==kr&&(c<min(b,x)||max(b,x)<c))te|=2;
			dp[a+1][x][11][b][te]=min(dp[a+1][x][11][b][te],dp[a][b][c][d][e]+ks);
			continue;
		}
		for(int y=0;y<W;y++){
			bool d2=false;
			for(int z=min(y,c);z<=max(y,c);z++)if(str[a][z]=='#')d2=true;
			if(str[a+1][y]=='#')d2=true;
			if(a+1==kr&&kc!=y)d2=true;
			if(a==SR&&a==KR&&min(b,x)<=c&&c<=max(b,x)&&min(c,y)<=b&&b<=max(c,y))continue;
			if(d2)continue;
			int ks=ABS(x-b)+1;
			int vt=0;
			for(int z=min(y,c);z<max(y,c);z++){
				bool iL=(min(b,x)<=z)&&(z<=max(b,x));
				bool iR=(min(b,x)<=z+1)&&(z+1<=max(b,x));
				if(!iL&&!iR)ks++;
				else if(!(iL&&iR)){
					if(!vt&&a==SR&&(z==SC||z+1==SC)){vt=1;ks++;}
			//		else if(!vt&&a==sr&&(z==sc||z+1==sc)){vt=1;ks++;}
					else ks+=2;
				}
			}
			if(d!=11&&a>KR&&min(b,d)<=c&&c<=max(b,d)&&min(b,x)<=c&&c<=max(b,x)){
				if(a-1==SR&&c==SC)ks--;
				else if(a-1==sr&&c==sc)ks--;
				else ks-=2;
			}
			if((SR!=a||y!=SC)&&min(b,x)<=y&&y<=max(b,x))ks+=2;
			else ks++;
			if(d!=11&&a>KR&&min(b,x)<=c&&c<=max(b,x)&&!(min(b,d)<=c&&c<=max(b,d)))ks++;
			int te=e;
			if(c<min(b,x)||max(b,x)<c)te|=2;
			if(b<min(c,y)||max(c,y)<b)te|=1;
		//	if(a==sr)te|=2;
		//	if(a==kr)te|=1;
		//	printf("%d %d %d %d %d -> %d %d %d %d %d: %d\n",a,b,c,d,e,a+1,x,y,b,te,ks);
			dp[a+1][x][y][b][te]=min(dp[a+1][x][y][b][te],dp[a][b][c][d][e]+ks);
		}
	}
}
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	H=a;W=b;
	for(int i=0;i<a;i++)scanf("%s",str[i]);
	for(int i=0;i<12;i++)for(int j=0;j<12;j++)for(int k=0;k<12;k++)for(int l=0;l<12;l++)
		dp[i][j][k][l][0]=dp[i][j][k][l][1]=dp[i][j][k][l][2]=dp[i][j][k][l][3]=99999999;
	for(int i=0;i<a;i++)for(int j=0;j<b;j++){
		if(str[i][j]=='s'){sr=i;sc=j;}
		if(str[i][j]=='k'){kr=i;kc=j;}
		if(str[i][j]=='S'){SR=i;SC=j;}
		if(str[i][j]=='K'){KR=i;KC=j;}
	}
	if(SR>KR){
		swap(SR,KR);
		swap(SC,KC);
		swap(sr,kr);
		swap(sc,kc);
	}
	if(SR==KR){
		dp[SR][SC][KC][11][0]=0;
	}else if(SR<KR){
		dp[SR][SC][11][11][1]=0;
	}else{
		dp[SR][SC][11][11][2]=0;
	}
	int ret=99999999;
	for(int i=0;i<a;i++){
		for(int j=0;j<12;j++){
			for(int k=0;k<12;k++){
				for(int l=0;l<12;l++){
					for(int m=0;m<4;m++){
						if(dp[i][j][k][l][m]>999999)continue;
						//printf("%d %d %d %d %d: %d\n",i,j,k,l,m,dp[i][j][k][l][m]);
						int t=0;
						if(j==11)t|=2;
						if(k==11)t|=1;
						if(j<W&&k<W&&k!=j)t|=3;
						if(i>=max(sr,kr)&&(m|t)==3)ret=min(ret,dp[i][j][k][l][m]);
						else upd(i,j,k,l,m);
					}
				}
			}
		}
	}
	if(SR>=sr||KR>=kr)ret=999999999;
	if(ret>999999)printf("CONTRACT\n");
	else printf("%d\n",ret);
}