2012-07-09 51 views
7

有一款有趣的遊戲叫做單人遊戲。它在m*n網格上播放。每個網格單元格中都有一個非負整數。您從0開始。您無法輸入其中包含整數0的單元格。您可以在任何想要的單元格開始和結束遊戲(當然,單元格中的數字不能爲0)。在每一步中,您都可以上下左右移動到相鄰的網格單元。您最後可以得到的分數是您路徑上的數字總和。但是最多可以輸入一次單元格。
網格步行高分

該遊戲的目的是讓你的分數儘可能高。

輸入:
輸入的第一行是整數T測試用例的個數。每個測試用例的第一行是一行,包含兩個整數mn,這是網格中的行數和列數。每個下一個的m線包含n空格隔開的整數D指示在對應的小區

輸出數:
對於每組測試輸出在一行中是可以在最後得到最高得分的整數。

限制條件:
T是小於7
D小於60001.
mn是小於8

樣品輸入:

4 
1 1 
5911 
1 2 
10832 0 
1 1 
0 
4 1 
0 
8955 
0 
11493 

樣品輸出:

5911 
10832 
0 
11493 

我嘗試過,但我的做法是工作很慢的7×7 grid.I我試圖遞歸訪問網格的每一個可能的路徑和比較每path.Below的總和是我的代碼

#include<iostream> 
#include <algorithm> 
#include <stdio.h> 
using namespace std; 

int max(int a,int b,int c, int d) 
{ 
int max = a; 
if(b>max) 
    max = b; 
if(c>max) 
    max = c; 
if(d>max) 
    max = d; 
return max; 
} 

int Visit_Component(int (*A)[8], int Visit[8][8], int m,int n , int row, int col) 
{ 

if ((row >= m) || (col >= n) || (col < 0) || (row < 0) || A[row][col] == 0   || Visit[row][col] == 1) 
{ 
    return 0; 
} 
else 
{ 

    Visit[row][col] = 1; 
    int a= 0,b=0,c=0,d=0,result =0; 
    a = Visit_Component(A, Visit,m,n, row+1, col); 
    b = Visit_Component(A, Visit,m,n, row, col +1); 
    c = Visit_Component(A, Visit,m,n, row, col -1); 
    d = Visit_Component(A, Visit,m,n, row-1, col); 
    Visit[row][col] = 0; 
    result = A[row][col] + max(a,b,c,d); 
    return result; 
} 
} 

int main(){ 

int T; 
scanf("%d",&T); 
for(int k =0; k<T;k++) 
{ 
    int N ; 
    int M; 
    int count = 0; 
    int maxcount = 0; 
    scanf("%d %d",&M,&N); 
    int C[8][8]; 
    int visit[8][8]; 
    for(int i = 0; i < M; i++) 
     for(int j = 0; j < N; j++) 
     { 
      scanf("%d",&C[i][j]); 
      visit[i][j] = 0; 
     } 
    for(int i= 0 ; i< M ; i++) 
    { 
     for(int j =0; j< N ; j++) 
     { 

      count = Visit_Component(C, visit,M,N, i, j); 
      if(count > maxcount) 
      { 
       maxcount = count; 
      } 
     } 
    } 
    printf("%d\n",maxcount); 
} 
return 0; 
} 

請給我建議如何優化這種方法或更好的算法。

+0

由於代碼有效,應該移動到代碼審查? – tomdemuyt 2012-07-09 19:10:42

+0

@tomdemuyt代碼正在工作,但我正在尋找此代碼中的優化,因爲它對於大型數據集的工作速度非常慢 – archit 2012-07-09 19:16:28

+0

這不是真正的代碼審查,因爲問題不在於如何更好地組織代碼,而是關於高效算法。 – biziclop 2012-07-09 20:17:13

回答

1

我能想到的一種優化方法是應用Dijkstra's algorithm。該算法將爲您提供特定源節點到所有目標節點的最小(在您的情況下爲最大)路徑。

在這個例子中,第一步是建立一個圖。

由於您不知道源節點的起始位置,因此您必須爲網格中的每個節點應用Dijkstra算法。時間複雜度會比遞歸方法更好,因爲對於特定的源節點,當找到最大路徑時,Dijkstra算法不會經歷所有可能的路徑。

+1

不幸的是,最長的路徑問題是NP完全的,所以Dijkstra(與負負荷週期不存在的假設一起工作)在這裏沒有幫助。你必須爲這個導出一些哈密頓路徑搜索啓發式。但比OP的版本更有效率。 – unkulunkulu 2012-07-10 06:23:05

+0

問題陳述明確指出每個網格單元中都有非負整數。 – user1168577 2012-07-10 06:29:56

+0

但迪克斯特拉也找到最短的路徑,爲了使它找到最長,你將不得不否定所有的權重... – unkulunkulu 2012-07-10 06:38:37

2

由於Wikipedia article on Travelling salesman problem暗示,有確切的算法,快速解決這個任務。但很難找到任何。而且他們很可能很複雜。

至於優化OP的方法,有幾種可能性。

從簡單的微觀優化開始比較容易:條件Visit[row][col] == 1滿足最高概率,所以它應該優先。

此外,用動態規劃優化分支定界算法以避免重複計算是合理的。在多達19個訪問單元的情況下,將計算結果存儲在簡單的哈希表中可將性能提高25%以上(對於某些改進的哈希表,可能會有更多)。下面是修改後的代碼片斷:

#include<iostream> 
#include <algorithm> 
#include <stdio.h> 
using namespace std; 

int max(int a,int b,int c, int d) 
{ 
    int max = a; 
    if(b>max) 
    max = b; 
    if(c>max) 
    max = c; 
    if(d>max) 
    max = d; 
    return max; 
} 

typedef unsigned long long ull; 
static const int HS = 10000019; 
static const int HL = 20; 
struct HT { 
    ull v; 
    int r; 
    int c; 
}; 
HT ht[HS] = {0}; 

int Visit_Component(
    int (*A)[8], ull& Visit, int m,int n , int row, int col, int x) 
{ 

    if ((Visit & (1ull << (8*row+col))) || (row >= m) || (col >= n) || 
    (col < 0) || (row < 0) || A[row][col] == 0) 
    { 
    return 0; 
    } 
    else 
    { 
    if (x < HL) 
    { 
     HT& h = ht[(Visit+4*row+col)%HS]; 
     if (h.v == Visit && h.r == row && h.c == col) 
     return 0; 
    } 

    Visit |= (1ull << (8*row+col)); 
    int a= 0,b=0,c=0,d=0,result =0; 
    a = Visit_Component(A, Visit,m,n, row+1, col, x+1); 
    b = Visit_Component(A, Visit,m,n, row, col +1, x+1); 
    c = Visit_Component(A, Visit,m,n, row, col -1, x+1); 
    d = Visit_Component(A, Visit,m,n, row-1, col , x+1); 
    Visit &= ~(1ull << (8*row+col)); 
    result = A[row][col] + max(a,b,c,d); 

    if (x < HL) 
    { 
     HT& h = ht[(Visit+4*row+col)%HS]; 
     h.v = Visit; 
     h.r = row; 
     h.c = col; 
    } 

    return result; 
    } 
} 

int main(){ 

    int T; 
    scanf("%d",&T); 
    for(int k =0; k<T;k++) 
    { 
    int N ; 
    int M; 
    int count = 0; 
    int maxcount = 0; 
    scanf("%d %d",&M,&N); 
    int C[8][8]; 
    ull visit = 0; 
    for(int i = 0; i < M; i++) 
     for(int j = 0; j < N; j++) 
     { 
      scanf("%d",&C[i][j]); 
     } 
    for(int i= 0 ; i< M ; i++) 
    { 
     for(int j =0; j< N ; j++) 
     { 

      count = Visit_Component(C, visit,M,N, i, j, 0); 
      if(count > maxcount) 
      { 
       maxcount = count; 
      } 
     } 
    } 
    printf("%d\n",maxcount); 
    } 
    return 0; 
} 

還有更多的改進可以通過預先處理所述輸入矩陣來完成。如果矩陣中沒有零或者角落中只有一個零,則可以對所有值進行求和。

如果只有一個零值(不在角落),最多一個非零值應該從總和中排除。如果您發明了一種算法,該算法確定單元的子集,則必須從中刪除其中一個單元,您可以從該子集中選擇最小值。

如果有兩個或更多個零值,使用分支定界算法:在這種情況下,它大約快20倍,因爲輸入矩陣中的每個零值意味着大約增加五倍的速度。

0
#include<iostream> 
#include<vector> 

using namespace std; 
vector<vector<int> >A; 
vector<vector<bool> >test; 
vector<vector<bool> >test1; 
int sum_max=0; 
int m,n; 
vector<vector<bool> > stamp; 
void color1(int i,int j,vector<vector<bool> >temp_vector,vector<vector<bool> > st,int summ){ 

    temp_vector[i][j]=false;summ+=A[i][j];st[i][j]=true; 
//1.1 
    if(i+1<m && temp_vector[i+1][j]){ 
    if(test1[i+1][j]){ 
        if(sum_max<(summ)){sum_max=summ;stamp=st;} 
        }  
else{color1(i+1,j,temp_vector,st,summ);} 
} 
    //1.2 
    if(i+1<m){if(!temp_vector[i+1][j]){ if(sum_max<(summ)){sum_max=summ;}}} 
    if(i+1>=m){if(sum_max<(summ)){sum_max=summ;}} 

    //2 
if(i-1>=0 && temp_vector[i-1][j]){ 
      if(test1[i-1][j]){ 
        if(sum_max<(summ)){sum_max=summ;} 
        }  
    else{ color1(i-1,j,temp_vector,st,summ);} 
    } 
    //2.2 
    if(i-1>=0){if(!temp_vector[i-1][j]){ if(sum_max<(summ)){sum_max=summ;}}} 
     if(i-1<0){if(sum_max<(summ)){sum_max=summ;}} 

    //3 
    if(j+1<n && temp_vector[i][j+1]){ 
     if(test1[i][j+1]){ 
         if(sum_max<(summ)){sum_max=summ;} 
        }  
    else{  color1(i,j+1,temp_vector,st,summ);}} 
    //3.2 
    if(j+1<n){if(!temp_vector[i][j+1]){ if(sum_max<(summ)){sum_max=summ;}}} 
     if(j+1>=n){if(sum_max<(summ)){sum_max=summ;}} 

    //4 
    if(j-1>=0 && temp_vector[i][j-1]){ 
     if(test1[i][j-1]){ 
        if(sum_max<(summ)){sum_max=summ;} 
        }  
else{  color1(i,j-1,temp_vector,st,summ);}} 
//4.2 
    if(j-1>=0){if(!temp_vector[i][j-1]){ if(sum_max<(summ)){sum_max=summ;}}} 
     if(j+1<0){if(sum_max<(summ)){sum_max=summ;}} 

} 


void color(int i,int j){ 
    test[i][j]=false; 
    if(i+1<m && test[i+1][j]){ 
    color(i+1,j);} 
    if(i-1>=0 && test[i-1][j]){ 
      color(i-1,j); 
} 
if(j+1<n && test[i][j+1]){ 
      color(i,j+1);} 
if(j-1>=0 && test[i][j-1]){color(i,j-1);} 

} 

int main(){ 
    int tc;cin>>tc; 
    for(int i=0;i<tc;i++){ 
     int mp,np; 
     cin>>mp; 
     cin>>np;m=mp;n=np;A.resize(m);test.resize(m);test1.resize(m);int sum=0; 
     vector<bool> ha1(m,1); 
     vector<bool> ha2(n,1); 
     for(int i=0;i<m;i++){A[i].resize(n);test[i].resize(n);test1[i].resize(n); 
       for(int j=0;j<n;j++){ 
         cin>>A[i][j];sum+=A[i][j]; 
                test[i][j]=true;test1[i][j]=false; 
                if(A[i][j]==0){test[i][j]=false;ha1[i]=false;ha2[j]=false;} 
         } 
       }cout<<endl; 
       for(int i=0;i<m;i++){cout<<" "<<ha1[i];} cout<<endl; 
       for(int i=0;i<n;i++){cout<<" "<<ha2[i];} cout<<endl; 
       cout<<"sum "<<sum<<"\n"; 
       int temp_sum=0; 
       for(int i=0;i<m;i++){ 
           for(int j=0;j<n;j++){//if(A[i][j]<=8845){cout<<"\nk "<<A[i][j]<<" "<<(8845-A[i][j]);} 
             if(test[i][j]){ 
                 if((i-1)>=0 && test[i-1][j] && (i+1)<m && test[i+1][j] && (j-1)>=0 && test[i][j-1] && (j+1)<n && test[i][j+1] && test[i-1][j-1] && test[i-1][j+1]&& test[i+1][j-1] && test[i+1][j+1]){ 
                    temp_sum+=A[i][j];test1[i][j]=true;} 

                 } 
                // cout<<test1[i][j]<<" "; 
             }//cout<<"\n"; 
             } 

//   /* 
       for(int i=0;i<m;i++){ 
           for(int j=0;j<n;j++){ 

             if(test1[i][j]){if(!((test1[i-1][j]||test1[i+1][j]) && (test1[i][j-1]||test1[i][j+1]))){ 
                         temp_sum-=A[i][j]; test1[i][j]=false;} 
             } 

                 // 
                // cout<<test1[i][j]<<" "; 
             }// 
             // cout<<"\n"; 
             } 
    //    */ 

       //cout<<"\n temp_sum is "<<temp_sum<<endl; 
       vector<vector<bool> > st(m,vector<bool>(n,0));st=test1; 
       for(int i=0;i<m;i++){ 
           for(int j=0;j<n;j++){ 
             if(test[i][j] && (!test1[i][j])){ 
                 color1(i,j,test,st,0); 

                 }}} 

      // cout<<"\nsum is "<<(sum_max+temp_sum)<<endl<<endl; 
      cout<<(sum_max+temp_sum)<<endl; 
     for(int i=0;i<m;i++){ 
           for(int j=0;j<n;j++){cout<<stamp[i][j]<<" ";} cout<<endl;} 
//   cout<<max<<endl; 
     A.clear(); 
     test.clear(); 
     test1.clear(); 
     sum_max=0; 
      } 


    cout<<endl;system("pause"); 
return 0; 
}