Ural 1519

Ural 1519

真-插头DP模板题,也是用插头DP的思想做的,括号表示法耗时比最小表示法略少,但是思路复杂小小,代码好难打啊,弄了很久才AC。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<cmath>
#include<string>
#include<vector>
#include<queue>

using namespace std;

#define inf 0x7fffffff
#define N 600007
#define LL long long

LL str[20];
LL maps[20][20],n,m;
LL ex,ey;

struct hashmap
{
	LL visit[N],next[N];
	LL h[N];
	LL num[N],cnt;
	void clear()
	{
		cnt = 0;
		memset(visit,-1,sizeof(visit));
	}
	void insert(LL x,LL y)
	{
		LL z = x%N;
		for(LL i = visit[z];i != -1;i = next[i])
		{
			if(h[i] == x)
			{
				num[i] += y;
				return ;
			}
		}
		next[cnt] = visit[z];
		num[cnt] = y;
		h[cnt] = x;
		visit[z] = cnt++;
		return ;
	}
}s[2];

void change(LL x,LL len)                             //数字变数组
{
	LL mark = 3;
	for(LL i = 0;i <= len;i++)
	{
		str[i] = x&mark;
		x >>= 2;
	}
}

LL changeover(LL len)                                 //数组转数字
{
	LL ans = 0;
	for(LL i = len;i >= 0;i--)
	{
		ans <<= 2;
		ans |= str[i];
	}
	return ans;
}

void get(LL len)                                       //换行
{
	for(LL i = len;i >= 1;i--)
	{
		str[i] = str[i - 1];
	}
	str[0] = 0;
}

LL fin(LL len,LL a)                                    //寻找匹配括号
{
	LL i,j;
	LL x;
	if(str[a] == 1)
	{
		for(i = a + 1,j = 0;i <= len;i++)
		{
			if(str[i] == 1)
				j++;
			if(str[i] == 2)
			{
				if(j == 0)
				{
					x = i;
					break;
				}
				else
					j--;
			}
		}
	}
	else
	{
		for(i = a - 1,j = 0;i >= 0;i--)
		{
			if(str[i] == 2)
				j++;
			if(str[i] == 1)
			{
				if(j == 0)
				{
					x = i;
					break;
				}
				else
					j--;
			}
		}
	}
	return x;
}

void adjust(LL len,LL a,LL b)                                 //调整括号匹配
{
	LL x = fin(len,a),y = fin(len,b);
	if(x < y)
	{
		str[x] = 1;
		str[y] = 2;
	}
	else
	{
		str[x] = 2;
		str[y] = 1;
	}
}

void dp(LL last,LL nxt,LL i,LL j,LL k)
{
	change(s[last].h[k],m);
	if(str[j] && str[j + 1] )
	{
		if(maps[i][j + 1])
				return ;
		if(str[j] == 1 && str[j + 1] == 2)
		{
			if(i == ex && j + 1 == ey)
			{
				str[j] = str[j + 1] = 0;
				if(j == m - 1)
					get(m);
				s[nxt].insert(changeover(m),s[last].num[k]);
			}
			else return ;
		}
		else
		{
			adjust(m,j,j + 1);
			str[j] = str[j + 1] = 0;
			if(j == m - 1)
					get(m);
			s[nxt].insert(changeover(m),s[last].num[k]);
		}
	}
	else if(str[j] || str[j + 1])
	{
		if(maps[i][j + 1] == 1)
			return ;
		LL t = max(str[j],str[j + 1]);
		str[j] = t;
		str[j + 1] = 0;
		if(j == m - 1)
		{
			get(m);
			s[nxt].insert(changeover(m),s[last].num[k]);
		}
		else
		{
			s[nxt].insert(changeover(m),s[last].num[k]);
			str[j] = 0;
			str[j + 1] = t;
			s[nxt].insert(changeover(m),s[last].num[k]);
		}
	}
	else
	{
		if(maps[i][j + 1] == 1)
		{
			if(j == m - 1)
			{
				get(m);
			}
			s[nxt].insert(changeover(m),s[last].num[k]);
		}
		else
		{
			if(j == m - 1)
				return ;
			str[j] = 1;str[j + 1] = 2;
			s[nxt].insert(changeover(m),s[last].num[k]);
		}
	}
}

LL solve()
{
	if(ex + ey == -2)
		return 0;
	LL i,j,k,l,flag = 0,nxt;
	s[flag].clear();
	s[flag].insert(0,1);
	for(i = 1;i <= n;i++)
	{
		for(j = 0;j < m;j++)
		{
			nxt = flag^1;
			s[nxt].clear();
			for(k = 0;k < s[flag].cnt;k++)
			{
				dp(flag,nxt,i,j,k);
			}
			flag ^= 1;
		}
	}
	for(i = 0;i < s[nxt].cnt;i++)
	{
		if(s[nxt].h[i] == 0)
			return s[nxt].num[i];
	}
	return 0;
}

int main()
{
	while(cin>>n>>m)
	{
		ex = ey = -1;
		char x;
		for(LL i = 1;i <= n;i++)
		{
			for(LL j = 1;j <= m;j++)
			{
				cin>>x;
				if(x == '*')
				{
					maps[i][j] = 1;
				}
				else
				{
					ex = i;
					ey = j;
					maps[i][j] = 0;
				}
			}
		}
		cout<<solve()<<endl;
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值