记录编号 87634 评测结果 AAAAAAAAAA
题目名称 [UVa 1214] 连线 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 10.740 s
提交时间 2014-02-06 15:08:28 内存使用 22.84 MiB
显示代码纯文本
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<vector>
#include<cstring>
#include<iomanip>
using namespace std;
typedef long long ll;
const int INF=0x7fffffff/2;
const int SIZEN=10;
int N,M;
int grid[SIZEN][SIZEN]={0};
class STATE{
public:
	int x,y;//当前应该在这一格放线
	int up[SIZEN];//上方的编号
	//这是上方的M个插头
	int left;//左侧的编号
	void clear(void){
		x=y=left=0;
		memset(up,0,sizeof(up));
	}
	int mdl(void){
		int ans=left;
		for(int i=1;i<=M;i++) ans=ans*3+up[i];
		return ans;
	}
	bool placeblock(int U,int D,int L,int R){//若这个放法不行就返回false,否则把S改成这个放法
		if(U&&x==1) return false;//不能通向边界
		if(L&&y==1) return false;
		if(D&&x==N) return false;
		if(R&&y==M) return false;
		if(L!=left) return false;//左不匹配
		if(U!=up[y]) return false;//上不匹配
		if(left>0&&up[y]>0&&left!=up[y]) return false;//左和上不匹配
		left=R;
		up[y]=D;
		y++;
		return true;
	}
};
int f[10][10][59050]={0};
int DP(STATE &S){
	/*
	一个合法方案只需满足五个条件:
	1:空格有0或2个插头
	2:2/3格有1个插头
	3:相邻两格插头必须对应(有对有,无对无)
	4:2和3插头不能相连
	5:不能有通向边界的插头
	*/
	if(S.y==M+1){
		S.left=0;//这个插头是无效的,其他插头没有变
		S.y=1,S.x++;
	}
	if(S.x==N+1) return 0;//到这里了一定合法
	int &ans=f[S.x][S.y][S.mdl()];
	if(ans>=0) return ans;
	ans=INF;
	STATE T;
	if(grid[S.x][S.y]<=1){//空格或障碍格
		T=S;if(T.placeblock(0,0,0,0)) ans=min(ans,DP(T));//可以不放
		if(grid[S.x][S.y]==0){//空格
			//如果放,就是连了两条边
			for(int t=1;t<=2;t++){//当前放一条t线
				//这条线的长度是一格,考虑到要是整数所以将半格认为是1
				T=S;if(T.placeblock(t,t,0,0)) ans=min(ans,DP(T)+2);
				T=S;if(T.placeblock(t,0,t,0)) ans=min(ans,DP(T)+2);
				T=S;if(T.placeblock(t,0,0,t)) ans=min(ans,DP(T)+2);
				T=S;if(T.placeblock(0,t,t,0)) ans=min(ans,DP(T)+2);
				T=S;if(T.placeblock(0,t,0,t)) ans=min(ans,DP(T)+2);
				T=S;if(T.placeblock(0,0,t,t)) ans=min(ans,DP(T)+2);
			}
		}
	}
	else{
		int t=grid[S.x][S.y]-1;//格子有2和3,但线对应的是1和2
		//这条线的长度是半格
		T=S;if(T.placeblock(t,0,0,0)) ans=min(ans,DP(T)+1);
		T=S;if(T.placeblock(0,t,0,0)) ans=min(ans,DP(T)+1);
		T=S;if(T.placeblock(0,0,t,0)) ans=min(ans,DP(T)+1);
		T=S;if(T.placeblock(0,0,0,t)) ans=min(ans,DP(T)+1);
	}
	return ans;
}
void work(void){
	memset(f,-1,sizeof(f));
	STATE S;
	S.clear();//这时所有的插头都是空的
	S.x=S.y=1;
	int ans=DP(S);
	if(ans==INF) printf("0\n");
	else printf("%d\n",ans/2);
}
bool read(void){
	scanf("%d%d",&N,&M);
	if(!N&&!M) return false;
	for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) scanf("%d",&grid[i][j]);
	return true;
}
int main(){
	freopen("manhattanwiring.in","r",stdin);
	freopen("manhattanwiring.out","w",stdout);
	while(read()) work();
	return 0;
}