7

一人遊びという面白いゲームがあります。m*nグリッド上でプレイされます。各グリッド セルには負でない整数があります。You start with a score of 0. 整数 0 を含むセルを入力することはできません。任意のセルでゲームを開始および終了できます (もちろん、セル内の数字が 0 になることはありません)。各ステップで、隣接するグリッド セルに上下左右に移動できます。最終的に獲得できるスコアは、パス上の数字の合計です。ただし、各セルに入力できるのは最大 1 回です。

ゲームの目的は、できるだけ高いスコアを獲得することです。

入力: 入力の最初の行は、テスト ケースの数の
整数です。各テスト ケースの最初の行は、グリッド内の行と列の数である2 つの整数をT含む 1行です。次の各行には、対応するセルの数値を示すスペースで区切られた整数が含まれますmnmnD

出力:
各テスト ケースに対して、最終的に取得できる最大スコアである 1 行の整数を出力します。

制約:
Tは 7 未満です。
Dは 60001 未満です。
mおよびnは 8 未満です。

サンプル入力:

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

サンプル出力:

5911
10832
0
11493

私はそれを試しましたが、私のアプローチは7x7グリッドに対して非常に遅く動作しています.グリッドのすべての可能なパスに再帰的にアクセスしようとしており、すべてのパスの合計を比較しています.以下は私のコードです.

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

このアプローチまたはより良いアルゴリズムを最適化する方法を教えてください。

4

3 に答える 3

2

巡回セールスマン問題に関するウィキペディアの記事が示唆するように、このタスクを迅速に解決する正確なアルゴリズムがあります。しかし、見つけるのは難しいです。そして、それらはおそらく複雑です。

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

また、入力行列を前処理することで、さらに多くの改善を行うことができます。行列にゼロがない場合、または隅にゼロが 1 つしかない場合は、すべての値を合計するだけです。

ゼロの値が 1 つしかない場合 (隅にない)、多くても 1 つのゼロ以外の値を合計から除外する必要があります。セルの 1 つを削除する必要があるセルのサブセットを決定するアルゴリズムを発明した場合、このサブセットから最小値を選択するだけで済みます。

ゼロ値が 2 つ以上ある場合は、分岐限定アルゴリズムを使用します。この場合、入力行列の各ゼロ値は約 5 倍の速度増加を意味するため、約 20 倍高速です。

于 2012-07-10T13:09:15.453 に答える
1

考えられる最適化の 1 つは、ダイクストラのアルゴリズムを適用することです。このアルゴリズムは、特定のソース ノードからすべての宛先ノードへの最小 (この場合は最大) パスを提供します。

この例では、最初のステップはグラフを作成することです。

また、開始するソース ノードがわからないため、グリッド内の各ノードにダイクストラのアルゴリズムを適用する必要があります。特定のソース ノードの場合、ダイクストラのアルゴリズムが最大パスを見つけるときに、すべての可能なパスを通過するわけではないため、時間計算量は再帰法よりも優れています。

于 2012-07-10T05:30:02.137 に答える
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;
}
于 2012-07-14T20:37:45.953 に答える