HDU 1964 Pipes 解题报告(插头DP)

    插头DP。格子间有value,求哈密顿回路value和最小。和Ural 1519类似,给每个状态更新最小的value值即可。

    代码如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=59999;
struct Node
{
    int H[maxn];
    int S[maxn];
    int N[maxn];
    int size;
    void init()
    {
        size=0;
        memset(H,-1,sizeof(H));
    }

    void push(int SS,int num)
    {
        int s=SS%maxn;
        while( ~H[s] && S[H[s]]!=SS )
        {
            s++;
            s%=maxn;
        }

        if(~H[s])
        {
            N[H[s]]=min(N[H[s]],num);
            return;
        }

        N[size]=num;
        S[size]=SS;
        H[s]=size++;
    }

    int get(int SS)
    {
        int s=SS%maxn;
        while( ~H[s] && S[H[s]]!=SS)
        {
            s++;
            s%=maxn;
        }

        if(~H[s])
            return N[H[s]];
        else
            return 0;
    }
} dp[2];
int now,pre;

int get(int S,int p,int l=2)
{
    return (S>>(p*l))&((1<<l)-1);
}

void set(int &S,int p,int v,int l=2)
{
    S^=get(S,p,l)<<(p*l);
    S^=(v&((1<<l)-1))<<(p*l);
}

int a[12][12];
int b[12][12];
int maze[12][12];

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int ans=~0U>>2;
		int n,m;
		scanf("%d%d%*c",&n,&m);
		memset(maze,0,sizeof(maze));
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				maze[i][j]=1;

		char str[1000];
		gets(str);
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		for(int i=1;i<n;i++)
		{
			gets(str);
			for(int j=1;j<m;j++)
				a[i-1][j]=str[j*2]-'0';
			gets(str);
			for(int j=0;j<m;j++)
				b[i][j]=str[j*2+1]-'0';
		}
		gets(str);
		for(int j=1;j<m;j++)
			a[n-1][j]=str[j*2]-'0';
		gets(str);

		now=1;
		pre=0;
		dp[now].init();
		dp[now].push(0,0);

		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				swap(now,pre);
				dp[now].init();

				for(int s=0;s<dp[pre].size;s++)
				{
					int S=dp[pre].S[s];
					int num=dp[pre].N[s];
					int p=get(S,j);
					int q=get(S,j+1);

					if(p==0 && q==0)
					{
						set(S,j,1);
						set(S,j+1,2);
						if(maze[i][j+1] && maze[i+1][j])
							dp[now].push(S,num);
					}
					else if(p>0 && q==0)
					{
						if(maze[i+1][j])
							dp[now].push(S,num+a[i][j]);
						set(S,j,0);
						set(S,j+1,p);
						if(maze[i][j+1])
							dp[now].push(S,num+a[i][j]);
					}
					else if(p==0 && q>0)
					{
						if(maze[i][j+1])
							dp[now].push(S,num+b[i][j]);
						set(S,j,q);
						set(S,j+1,0);
						if(maze[i+1][j])
							dp[now].push(S,num+b[i][j]);
					}
					else if(p==1 && q==1)
					{
						int find=1;
						for(int k=j+2;k<=m;k++)
						{
							int v=get(S,k);
							if(v==2) find--;
							else if(v==1) find++;

							if(find==0)
							{
								set(S,j,0);
								set(S,j+1,0);
								set(S,k,1);
								dp[now].push(S,num+a[i][j]+b[i][j]);
								break;
							}
						}
					}
					else if(p==2 && q==2)
					{
						int find=1;
						for(int k=j-1;k>=0;k--)
						{
							int v=get(S,k);
							if(v==1) find--;
							else if(v==2) find++;

							if(find==0)
							{
								set(S,j,0);
								set(S,j+1,0);
								set(S,k,2);
								dp[now].push(S,num+a[i][j]+b[i][j]);
								break;
							}
						}
					}
					else if(p==2 && q==1)
					{
						set(S,j,0);
						set(S,j+1,0);
						dp[now].push(S,num+a[i][j]+b[i][j]);
					}
					else if(p==1 && q==2)
					{
						if(i==n-1 && j==m-1)
						{
							set(S,j,0);
							set(S,j+1,0);
							dp[now].push(S,num+a[i][j]+b[i][j]);
						}
					}
				}
			}

			for(int s=0;s<dp[now].size;s++)
				dp[now].S[s]<<=2;
		}

		printf("%d\n",dp[now].get(0));
	}
}

    最小表示法:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;

const int maxn=59999;
const int L=3;
int now,pre;
int n,m;
int ans;
int endx,endy;
int maze[15][15];
int a[15][15];
int b[15][15];
int code[15],ch[15];
struct Node
{
	int h[maxn];
	int n[maxn];
	LL s[maxn];
	int size;
	void init()
	{
		memset(h,-1,sizeof(h));
		size=0;
	}

	void push(LL ss,int num)
	{
		int i=ss%maxn;
		while( ~h[i] && s[h[i]]!=ss )
			i=(i+1)%maxn;
		if( ~h[i] )
		{
			n[h[i]]=min(n[h[i]],num);
		}
		else
		{
			s[size]=ss;
			n[size]=num;
			h[i]=size++;
		}
	}
} dp[2];

void decode(LL s)
{
	for(int i=0;i<=m;i++)
		code[i]=s&((1<<L)-1),s>>=L;
}

LL encode()
{
	memset(ch,-1,sizeof(ch));
	ch[0]=0;
	LL s=0;
	int cnt=1;

	for(int i=m;i>=0;i--)
	{
		if( ch[code[i]]==-1 ) ch[code[i]]=cnt++;
		s<<=L;
		s|=ch[code[i]];
	}
	return s;
}

void shift()
{
	for(int s=0;s<dp[now].size;s++)
		dp[now].s[s]<<=L;
}

void merge(int a,int b)
{
	for(int i=0;i<=m;i++) if(code[i]==a)
		code[i]=b;
}

void doGrid(int i,int j)
{
	for(int s=0;s<dp[pre].size;s++)
	{
		decode(dp[pre].s[s]);
		int num=dp[pre].n[s];
		int left=code[j];
		int up=code[j+1];
		int ma=max(left,up);
		int mi=min(left,up);
		int val=0;
		if(left) val+=a[i][j];
		if(up)   val+=b[i][j];

		if(ma==0)
		{
			if(maze[i][j+1] && maze[i+1][j])
			{
				code[j]=code[j+1]=13;
				dp[now].push(encode(),num);
			}
		}
		else if(mi==0)
		{
			if(maze[i+1][j])
			{
				code[j]=ma;
				code[j+1]=0;
				dp[now].push(encode(),num+val);
			}
			if(maze[i][j+1])
			{
				code[j]=0;
				code[j+1]=ma;
				dp[now].push(encode(),num+val);
			}
		}
		else if(left==up)
		{
			if(i==n-1 && j==m-1)
			{
				code[j]=0;
				code[j+1]=0;
				if(encode()==0) ans=max(ans,num+val);
			}
		}
		else
		{
			code[j]=code[j+1]=0;
			merge(left,up);
			dp[now].push(encode(),num+val);
		}
	}
}

void solve()
{
	now=1,pre=0;
	ans=0;
	dp[now].init();
	dp[now].push(0,0);

	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++)
		{
			swap(now,pre);
			dp[now].init();
			doGrid(i,j);
		}
		shift();
	}
}

void init()
{
	scanf("%d%d%*c",&n,&m);
	memset(maze,0,sizeof(maze));
	for(int i=0;i<n;i++)
		for(int j=0;j<m;j++)
			maze[i][j]=1;

	char str[1000];
	gets(str);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	for(int i=1;i<n;i++)
	{
		gets(str);
		for(int j=1;j<m;j++)
			a[i-1][j]=str[j*2]-'0';
		gets(str);
		for(int j=0;j<m;j++)
			b[i][j]=str[j*2+1]-'0';
	}
	gets(str);
	for(int j=1;j<m;j++)
		a[n-1][j]=str[j*2]-'0';
	gets(str);
}

int main()
{
	int T;
	int cas=1;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		init();
		solve();
		printf("%d\n",ans);
	}
}


你可能感兴趣的:(dp,插头DP)