1. 程式人生 > >【Poj3133】Manhattan Wiring (插頭DP)

【Poj3133】Manhattan Wiring (插頭DP)

但是 之間 main man sin pri cstring urn break

Description

題目大意:給你個N x M(1≤N, M≤9)的矩陣,0表示空地,1表示墻壁,2和3表示兩對關鍵點。現在要求在兩對關鍵點之間建立兩條路徑,其中兩條路徑不可相交或者自交(就是重復經過同一格子),並且不能經過墻壁,路徑只能從一個格子走到相鄰的下一格子。求兩條路徑最少需要經過的格子數減二。如果不存在解,輸出0。

Solution

插頭DP,用三進制來表示輪廓線,0表示沒有插頭,1表示“2”的的插頭,2表示“3”的插頭

  1. 對於0的格子:00 -> 00,11,22;01/10 -> 01/10;02/20 -> 02/20;11/22 -> 00。
  2. 對於1的格子:00 -> 00。
  3. 對於2的格子:01/10 -> 00,00 -> 01/10。
  4. 對於3的格子:02/20 -> 00,00 -> 02/20。

但是if太多會超時,所以有必要減少if語句的使用

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 11
using namespace std;

const int A[]={1,3,9,27,81,243,729,2187,6561,19683,59049};
int n,m,g[N][N],dp[N][N][59049];

inline int read(){
    int x=0,f=1;char
ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main(){ while(~scanf("%d%d",&n,&m)&&n+m){ memset(g,0
,sizeof(g)); memset(dp,0x3f,sizeof(dp)); for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)g[i][j]=read(); dp[0][m][0]=0; for(int i=1;i<=n;++i){ for(int j=0;j<A[m];++j)//A[m] dp[i][0][j*3]=dp[i-1][m][j]; for(int j=1;j<=m;++j){ for(int k=0;k<A[m+1];++k){//A[m+1] if (j==m&&k>=A[m]) break; int a=(k/A[j-1])%3,b=(k/A[j])%3; if(g[i][j]==1){ if(a==0&&b==0) dp[i][j][k]=dp[i][j-1][k]; }else if(g[i][j]==2){//min,+1 if(a==1&&b==0) dp[i][j][k]=dp[i][j-1][k-A[j-1]]+1; else if(a==0&&b==1) dp[i][j][k]=dp[i][j-1][k-A[j]]+1; else if(a==0&&b==0) dp[i][j][k]=min(dp[i][j-1][k+A[j-1]],dp[i][j-1][k+A[j]])+1; }else if(g[i][j]==3){ if(a==2&&b==0) dp[i][j][k]=dp[i][j-1][k-2*A[j-1]]+1; else if(a==0&&b==2) dp[i][j][k]=dp[i][j-1][k-2*A[j]]+1; else if(a==0&&b==0) dp[i][j][k]=min(dp[i][j-1][k+2*A[j-1]],dp[i][j-1][k+2*A[j]])+1; } else if(g[i][j]==0){ if(a==0&&b==0) dp[i][j][k]=min(dp[i][j-1][k],min(dp[i][j-1][k+A[j]+A[j-1]]+1,dp[i][j-1][k+2*A[j]+2*A[j-1]]+1)); else if(a==0&&b>0) dp[i][j][k]=min(dp[i][j-1][k],dp[i][j-1][k+b*A[j-1]-b*A[j]])+1; else if(a>0&&b==0) dp[i][j][k]=min(dp[i][j-1][k],dp[i][j-1][k+a*A[j]-a*A[j-1]])+1; else if(a&&b&&a==b) dp[i][j][k]=dp[i][j-1][k-a*A[j]-a*A[j-1]]+1; } if (i==n&&j==m) break; } } } if(dp[n][m][0]<0x3f3f3f3f) printf("%d\n",dp[n][m][0]-2); else printf("0\n"); } return 0; }

【Poj3133】Manhattan Wiring (插頭DP)