1094 - Channel

本文介绍了一种解决农场灌溉渠最优路径寻找问题的算法。该算法通过复杂的位运算和状态压缩来高效地确定灌溉渠从农场一端到另一端的最长路径,同时避开障碍并确保水流畅通无阻。

Joe, a former champion coder, has finally bought the farm. No, no, he's alive and well; he merely made use of his vast programming competition winnings to purchase his ancestral farm. He hopes to retire and spend the rest of his days tending cows (for some reason, he now considers himself an expert on cows).

Sadly, Farmer Joe's simple bucolic ambitions are not to be. His farm is situated in a cold, northern climate - too cold for cows! What's worse, the climate is dry and ill-suited for growing crops. Joe now realizes that he will have to set up an irrigation scheme for his field. This scheme involves diverting part of a river into a long, winding channel through his field. Since the crops nearest the channel will thrive, the longer the channel, the better.


His field is a long rectangular strip of land divided into unit squares. Each square either has dirt, represented by `.', or an immovable rock, represented by `#'. The irrigation channel, which is one square wide, enters his land in the upper left corner and exits it in the lower right. The channel cannot pass through rocks, of course. It is important that this channel never touches itself, even at a corner (or else the water will seep through and take a shortcut). Figure 3 and Figure 4 contain examples of the channel touching itself.

\epsfbox{p4789.eps}

Unfortunately, Joe's best programming days are long behind him. He has a straightforward solution but it turns out to be far too time consuming. Can you help him figure out the optimal placement of this channel?

Input 

Input consists of several test cases. Each test case starts with a line containing r, the number of rows in his field (2$ \le$r$ \le$20), and c, the number of columns (2$ \le$c$ \le$9). The next r lines each contain a string of length c, describing his field.

The last test case is followed by a line containing two zeros.

Output 

For each test case, display the case number. On the following r lines show how to place the longest possible channel in the field, subject to the above restrictions. Use the character `C' for the channel. There will always be a unique solution. Follow the format in the sample output. Print a blank line after the output for each test case.

Sample Input 

3 3 
.#. 
... 
.#. 
6 7 
....... 
....... 
....... 
....#.. 
....... 
.#..... 
0 0

Sample Output 

Case 1: 
C#. 
CCC 
.#C 

Case 2: 
CCCCCCC 
......C 
CCCCCCC 
C...#.. 
CCC.CCC 
.#CCC.C







#include<stdio.h>
#include<string.h>
#include<stdlib.h>
const int MAXN=1100007;
const int MAXR=20;
const int MAXC=10;
typedef unsigned char _char;
struct Tstack
{
	static const int MAXS=MAXN;
	int len;
	int data[MAXS];
	void clear(void){len=0;}
	void push(int k){data[++len]=k;}
	int pop(void){return data[len--];}
	inline bool empty(){return len==0;}
};

const int exp4[]={0x000003,0x00000C,0x000003,0x000030,0x0000C0,0x000300,0x000C00,
				  0x003000,0x00C000,0x030000,0x0C0000,0x30000,0xC00000};
const int div4[]={0,2,4,6,8,10,12,14,16,18,20,22};
int r,c;
_char f[MAXR][MAXC][MAXN];
int l[MAXR][MAXC][MAXN];
Tstack s[2];
bool a[MAXR][MAXC];
int ans[MAXR][MAXC];
bool path[MAXR][MAXC];
int maxlen=0;

void init()
{
	int i,j;
	char str[20];
	for(i=0;i<r;++i)
	{
		scanf("%s",str);
		for(j=0;j<c;++j)
			if(str[j]=='#')
				a[i][j]=0;
			else
				a[i][j]=1;
	}
}

inline _char max(_char a,_char b)
{
	return a>b?a:b;
}

inline int getbit(int k,int n)
{
	return ((k&exp4[n])>>div4[n]);
}

inline int changebit(int k,int n,int m)
{
	return k-(k&exp4[n])+(m<<div4[n]);
}

inline int changeL(int k,int j)
{
	k=changebit(changebit(k,j,3),j+1,3);
	int t=j+1,s=1,i;
	while(s>0)
	{
		++t;
		i=getbit(k,t);
		if(i==1)
			++s;
		else if(i==2)
			--s;
	}
	k=changebit(k,t,1);
	return k;
}

inline int changeR(int k,int j)
{
	k=changebit(changebit(k,j,3),j+1,3);
	int t=j,s=1,i;
	while(s>0)
	{
		--t;
		i=getbit(k,t);
		if(i==2)
			++s;
		else if(i==1)
			--s;
	}
	k=changebit(k,t,2);
	return k;
}

inline void updata(_char hash[],int path[],Tstack &s,int k,_char v,int last)
{
	if(hash[k]==0xff)
	{
		hash[k]=v;
		path[k]=last;
		s.push(k);
	}
	else if(v>hash[k])
	{
		hash[k]=v;
		path[k]=last;
	}
}

inline bool ok(int k)
{
	int i,j;
	for(i=0;i<c;++i)
	{
		j=getbit(k,i);
		if((j==1)||(j==2))
			return false;
	}
	return getbit(k,c)==1;
}

void solve()
{
	int now=0;
	int last=1;
	int i,j,k,t,left,up,d;
	memset(f,0xff,sizeof(f));
	updata(f[0][0],l[0][0],s[now],1,0,-1);
	for(i=0;i<r;++i)
	{
		for(j=0;j<c;++j)
		{
			now^=1;
			last^=1;
			s[now].clear();
			if(s[last].len>maxlen)
				maxlen=s[last].len;
			while(!s[last].empty())
			{
				k=s[last].pop();
				d=f[i][j][k];
				left=getbit(k,j);
				up=getbit(k,j+1);
				if(a[i][j])
				{
					if((left==2)&&(up==1))
					{
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,3),j+1,3),d+1,k);
					}
					else if((left==0)&&(up==0))
					{
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,1),j+1,2),d+1,k);
					}
					else if((left==1)&&(up==1))
					{
						updata(f[i][j+1],l[i][j+1],s[now],changeL(k,j),d+1,k);
					}
					else if((left==2)&&(up==2))
					{
						updata(f[i][j+1],l[i][j+1],s[now],changeR(k,j),d+1,k);
					}
					else if((left==0)&&(up<3))
					{
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,up),j+1,3),d+1,k);
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,3),j+1,up),d+1,k);
					}
					else if((left<3)&&(up==0))
					{
						if((j+2>c)||(getbit(k,j+2)!=3))
							updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,left),j+1,3),d+1,k);
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,3),j+1,left),d+1,k);
					}
				}
				if(((left==0)||(left==3))&&((up==0)||(up==3)))
				{
					if((up==3)&&((j+2>c)||(getbit(k,j+2)==0)))
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,0),j+1,3),d,k);
					else
						updata(f[i][j+1],l[i][j+1],s[now],changebit(changebit(k,j,0),j+1,0),d,k);
				}
			}
		}
		if(i==(r-1))
			break;
		now^=1;
		last^=1;
		s[now].clear();
		while(!s[last].empty())
		{
			k=s[last].pop();
			d=f[i][c][k];
			left=getbit(k,c);
			if((left==0)||(left==3))
				updata(f[i+1][0],l[i+1][0],s[now],changebit(k,c,0)<<2,d,k);
		}
	}
	int anslen=-1;
	k=-1;
	while(!s[now].empty())
	{
		k=s[now].pop();
		if(ok(k)&&(f[i][c][k]>anslen))
		{
			anslen=f[i][c][k];
			t=k;
		}
	}
	for(i=r-1;i>=0;--i)
		for(j=c;j>=0;--j)
		{
			k=t;
			ans[i][j]=k;
			t=l[i][j][k];
		}
	d=0;
	memset(path,0,sizeof(path));
	for(i=0;i<r;++i)
		for(j=0;j<=c;++j)
		{
			k=f[i][j][ans[i][j]];
			if(k>d)
				path[i][j]=true;
			d=k;
		}
	for(i=0;i<r;++i)
	{
		for(j=0;j<c;++j)
		{
			if(path[i][j+1])
				printf("C");
			else if(!a[i][j])
				printf("#");
			else
				printf(".");
		}
		printf("\n");
	}
}

int main()
{
	int CASE=0;
	maxlen=0;
	while(scanf("%d%d",&r,&c)&&(r||c))
	{
		printf("CASE %d:\n",++CASE);
		init();
		solve();
		printf("\n");
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不仅仅是寻找

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值