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;
}


### 曼哈顿对齐算法及其在计算机图形学中的应用 曼哈顿对齐(Manhattan Alignment)是一种几何约束方法,在许多领域中被广泛应用,尤其是在计算机图形学、机器人定位以及计算几何等领域。该技术的核心在于通过特定的方向约束来简化复杂的空间结构表示。 #### 定义与基本原理 曼哈顿对齐通常指的是对象或空间布局沿着笛卡尔坐标系的主要轴线方向排列的方式。这种排列方式可以显著减少数据处理的复杂度并提高效率。例如,在三维场景重建或者地图绘制过程中,建筑物边缘往往会被假设为平行于X-Y-Z轴之一[^1]。这种方法不仅有助于降低噪声干扰的影响,还能使后续操作更加高效。 #### 实现细节 为了实现曼哈顿对齐,一般会采用如下策略: 1. **角度调整**: 对输入模型进行旋转变换直到其主要特征向量尽可能接近标准正交基底。 ```python import numpy as np def align_to_manhattan(points): covariance_matrix = np.cov(points.T) eigenvalues, eigenvectors = np.linalg.eigh(covariance_matrix) # Sort by descending order of variance explained. sorted_indices = np.argsort(eigenvalues)[::-1] aligned_axes = eigenvectors[:, sorted_indices].T rotation_matrix = aligned_axes @ np.diag([np.sign(aligned_axes[i][i]) for i in range(3)]) return points @ rotation_matrix.T ``` 2. **边界框拟合**: 使用最小包围盒(Minimum Bounding Box)技术找到最贴近目标形状且满足条件的新位置集合[^4]。 上述代码片段展示了如何基于协方差矩阵分解得到适合的数据转换参数从而完成初步校准过程。 #### 应用案例分析 - 在多机器人全局定位任务里,语义直方图匹配法利用了类似的思路来进行环境建模以便更精确地估计各自主体间相对位姿关系; - 另外像声呐信号处理方面也有涉及加权节点映射等概念用于解决局部化难题[^3]; 综上所述,无论是理论研究还是实际工程开发当中,“曼哈顿对齐”都扮演着不可或缺的角色。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值