码迷,mamicode.com
首页 > 其他好文 > 详细

【POJ3133】Manhattan Wiring (插头dp)

时间:2020-05-31 16:26:04      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:sse   ems   printf   nec   you   getchar   cells   nes   only   

Manhattan Wiring

题意:

There is a rectangular area containing n × m cells. Two cells are marked with “2”, and another two with “3”. Some cells are occupied by obstacles. You should connect the two “2”s and also the two “3”s with non-intersecting lines. Lines can run only vertically or horizontally connecting centers of cells without obstacles.

Lines cannot run on a cell with an obstacle. Only one line can run on a cell at most once. Hence, a line cannot intersect with the other line, nor with itself. Under these constraints, the total length of the two lines should be minimized. The length of a line is defined as the number of cell borders it passes. In particular, a line connecting cells sharing their border has length 1.
大意:将2,2连接,3,3连接,两条路径不相交求长度最小值

思路:

因为只用求序列的最小值,所以也不需要记录括号序列,只用区分是连接\(2\)还是连接\(3\)

\(dp\)中存四进制数,有1表示连2的插头,有2表示连3的插头,然后分开讨论

\(b_1\)表示左插头的值,\(b_2\)表示上插头的值

点为1

只能转移空格子

点为 2/3

1、只有左插头或者上插头,标号相同时可以转移,代表是终点

2、既没有左插头也没有右插头,加一个向右或者向下的插头,编号就是这个格子的值

3、既有左又有上不合法

点为0

1、如果\(!(b1|b2)\)

①不加

②加一个右和下插头,标号为2或3

2、\(b_1\)&\(b_2\)

①如果标号相同,直接连上

②不相同,不合法

3、\(b_1|b_2\)

如果是左插头,多加向右或者向下的

如果是上插头,同理

最后的答案用最后一个点

//POJ 3133
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
bool cur1;
void Rd(int &res) {
	res=0;
	char c;
	while(c=getchar(),c<48);
	do res=(res<<1)+(res<<3)+(c^48);
	while(c=getchar(),c>=48);
}
#define M 300005
const int Mod=299987;
int n,m,a[15][15],op,cnt[2],ex,ey,pr[1<<20],la[M],to[2][1<<20],inv[15],ans=0,dp[2][M];
void Min(int &x,int y) {
	if(x==-1||x>y)x=y;
}
void add(int bit,int v) {
	int u=(bit%Mod)+1;
	for(int i=la[u]; i; i=pr[i])
		if(to[op][i]==bit) {
			Min(dp[op][i],v);
			return;
		}
	to[op][++cnt[op]]=bit,pr[cnt[op]]=la[u],la[u]=cnt[op],dp[op][cnt[op]]=v;
}
bool cur2;
void Print(int x) {
	for(int i=0; i<=m; i++)printf("%d",x%4),x>>=2;
}
int main() {
	inv[0]=1;
	for(int i=1; i<=10; i++)inv[i]=(inv[i-1]<<2);
	while(1) {
		Rd(n),Rd(m);
		if(!(n|m))break;
		int ex,ey;
		for(int i=1; i<=n; i++)for(int j=1; j<=m; j++)Rd(a[i][j]);
		for(int i=1;i<=n;i++)a[i][m+1]=1;
		for(int j=1;j<=m;j++)a[n+1][j]=1;
		memset(dp,63,sizeof(dp));
		memset(la,0,sizeof(la));
		int res=inv[m+1]-1;
		op=0,cnt[0]=1,to[0][1]=0,dp[0][1]=0;
		for(int i=1; i<=n; i++) {
			for(int k=1; k<=cnt[op]; k++)to[op][k]<<=2,to[op][k]&=res;
			for(int j=1; j<=m; j++) {
				op^=1,cnt[op]=0,memset(la,0,sizeof(la));
				for(int k=1; k<=cnt[op^1]; k++) {
					int v=dp[op^1][k],od=to[op^1][k],b1=((od>>(2*(j-1)))%4),b2=((od>>(2*j))%4);
					if(a[i][j]==1) {
						if(!(b1|b2))add(od,v);
					} else if(!a[i][j]) {
						if(!(b1|b2)) {
							add(od,v);
							if((a[i][j+1]!=1)&&(a[i+1][j]!=1))add(od+inv[j-1]+inv[j],v+1),add(od+2*inv[j-1]+2*inv[j],v+1);
						} else if(b1&&b2) {
							if(b1==b2)add(od-inv[j-1]*b1-inv[j]*b2,v+1);
						} else if(b1) {
							if(a[i+1][j]!=1)add(od,v+1);
							if(a[i][j+1]!=1)add(od-inv[j-1]*b1+inv[j]*b1,v+1);
						} else if(b2) {
							if(a[i][j+1]!=1)add(od,v+1);
							if(a[i+1][j]!=1)add(od+inv[j-1]*b2-inv[j]*b2,v+1);
						}
					} else {
						if(!(b1|b2)) {
							if(a[i][j+1]!=1)add(od+inv[j]*(a[i][j]-1),v+1);
							if(a[i+1][j]!=1)add(od+inv[j-1]*(a[i][j]-1),v+1);
						} else if(b1&&b2);
						else if(b1) {
							if(b1==a[i][j]-1)add(od-inv[j-1]*b1,v+1);
						} else {
							if(b2==a[i][j]-1)add(od-inv[j]*b2,v+1);
						}
					}
				}
			}
		}
		int ans=-1;
		for(int k=1; k<=cnt[op]; k++)if(!to[op][k])Min(ans,dp[op][k]);
		if(ans==-1)puts("0");
		else printf("%d\n",ans-2);
	}
	return 0;
}

【POJ3133】Manhattan Wiring (插头dp)

标签:sse   ems   printf   nec   you   getchar   cells   nes   only   

原文地址:https://www.cnblogs.com/cly1231/p/13019001.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!