uvalive3620Manhattan Wiring

本文介绍了一种使用轮廓线动态规划解决特定类型路径寻找问题的方法。针对一个n*m矩阵,矩阵中有两个2和两个3的目标,需要找到连接相同数字且不相交路径的最短距离。文章详细展示了如何通过3进制状态表示来实现这一目标,并提供了完整的代码示例。

链接:http://acm.hust.edu.cn/vjudge/problem/11229

题意:给定一个n*m的矩阵,矩阵中有两个2和两个3,其他的为0/1,0表示空地,1表示障碍。要求将2连到2,3连到3并且两条线不能相交,求最短距离。

分析:大白书轮廓线dp例题,用3进制保存状态,枚举所有转移时的状态。注意新的一行开始时要将上一行最后那个点的状态的轮廓线右移一位。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=12;
const int mod=1000000007;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const ll MAX=1000000000;
const double pi=acos(-1.0);
typedef double db;
typedef unsigned long long ull;
int t[N],s[N],ma[N][N],dp[2][60000],f[60000][10];
void deal(int n) {
    int i,j;
    t[0]=1;s[0]=2;
    for (i=1;i<N;i++) t[i]=t[i-1]*3,s[i]=t[i]*2;
    for (i=0;i<n;i++)
        for (j=0;j<10;j++) f[i][j]=(i/t[j])%3;
}
int main()
{
    int i,j,k,n,m,mx,now,pre,L,U,news,newt,last;
    deal(60000);
    while (scanf("%d%d", &n, &m)&&(n||m)) {
        for (i=0;i<n;i++)
            for (j=0;j<m;j++) scanf("%d", &ma[i][j]);
        now=pre=dp[0][0]=0;mx=t[m+1]-1;
        for (i=1;i<=mx;i++) dp[0][i]=100;
        for (i=0;i<n;i++)
            for (j=0;j<m;j++) {
                pre=now;now^=1;
                for (k=0;k<=mx;k++) dp[now][k]=100;
                for (k=0;k<=mx;k++)
                if (dp[pre][k]!=100) {
                    if (j==0&&k*3>=t[m+1]) continue ;
                    j==0 ? last=k*3:last=k;
                    L=f[last][j];U=f[last][j+1];
                    if (ma[i][j]==0) {
                        newt=news=last;
                        if (L==0&&U==0) {
                            newt+=t[j]+t[j+1];news+=s[j]+s[j+1];
                            dp[now][last]=min(dp[now][last],dp[pre][k]);
                            dp[now][newt]=min(dp[now][newt],dp[pre][k]+1);
                            dp[now][news]=min(dp[now][news],dp[pre][k]+1);
                        } else if (L==0&&U==1) {
                            newt+=t[j]-t[j+1];
                            dp[now][last]=min(dp[now][last],dp[pre][k]+1);
                            dp[now][newt]=min(dp[now][newt],dp[pre][k]+1);
                        } else if (L==0&&U==2) {
                            news+=s[j]-s[j+1];
                            dp[now][last]=min(dp[now][last],dp[pre][k]+1);
                            dp[now][news]=min(dp[now][news],dp[pre][k]+1);
                        } else if (L==1&&U==0) {
                            newt+=t[j+1]-t[j];
                            dp[now][last]=min(dp[now][last],dp[pre][k]+1);
                            dp[now][newt]=min(dp[now][newt],dp[pre][k]+1);
                        } else if (L==1&&U==1) {
                            newt-=t[j]+t[j+1];
                            dp[now][newt]=min(dp[now][newt],dp[pre][k]+1);
                        } else if (L==2&&U==0) {
                            news+=s[j+1]-s[j];
                            dp[now][last]=min(dp[now][last],dp[pre][k]+1);
                            dp[now][news]=min(dp[now][news],dp[pre][k]+1);
                        } else if (L==2&&U==2) {
                            news-=s[j]+s[j+1];
                            dp[now][news]=min(dp[now][news],dp[pre][k]+1);
                        }
                    } else if (ma[i][j]==1) {
                        if (L==0&&U==0) dp[now][last]=min(dp[now][last],dp[pre][k]);
                    } else if (ma[i][j]==2) {
                        if (L==0&&U==0) {
                            dp[now][last+t[j]]=min(dp[now][last+t[j]],dp[pre][k]);
                            dp[now][last+t[j+1]]=min(dp[now][last+t[j+1]],dp[pre][k]);
                        }
                        if (L==1&&U==0) {
                            dp[now][last-t[j]]=min(dp[now][last-t[j]],dp[pre][k]);
                        }
                        if (L==0&&U==1) {
                            dp[now][last-t[j+1]]=min(dp[now][last-t[j+1]],dp[pre][k]);
                        }
                    } else {
                        if (L==0&&U==0) {
                            dp[now][last+s[j]]=min(dp[now][last+s[j]],dp[pre][k]);
                            dp[now][last+s[j+1]]=min(dp[now][last+s[j+1]],dp[pre][k]);
                        }
                        if (L==2&&U==0) {
                            dp[now][last-s[j]]=min(dp[now][last-s[j]],dp[pre][k]);
                        }
                        if (L==0&&U==2) {
                            dp[now][last-s[j+1]]=min(dp[now][last-s[j+1]],dp[pre][k]);
                        }
                    }
                }
            }
        if (dp[now][0]!=100) printf("%d\n", dp[now][0]+2);
        else printf("0\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值