2012-07-09 9 views
7

Istnieje interesująca gra o nazwie jedna osoba. Gra się na siatce m*n. W każdej komórce siatki znajduje się nieujemna liczba całkowita. Zaczynasz z wynikiem 0. Nie możesz wprowadzić komórki zawierającej liczbę całkowitą 0. Możesz rozpocząć i zakończyć grę w dowolnej komórce (oczywiście numer w komórce nie może być 0). Na każdym kroku możesz iść w górę, w dół, w lewo i w prawo do sąsiedniej komórki siatki. Wynik, który można uzyskać w końcu, jest sumą liczb na twojej ścieżce. Ale możesz wpisać każdą komórkę co najwyżej raz.
Wysoki wynik w siatce spacerowej

Celem gry jest uzyskanie jak najwyższego wyniku.

Wejście:
Pierwszą linią wejściową jest liczba całkowita T liczba przypadków testowych. Pierwszy wiersz każdego przypadku testowego to pojedyncza linia zawierająca 2 liczby całkowite m i n, która jest liczbą wierszy i kolumn w siatce. Każdy z kolejnych z m wierszy zawiera n oddzielonych spacjami liczb całkowitych D wskazaniem liczby w odpowiedniej komórce

wyjściowa:
dla każdego wyjścia przypadków testowych liczbę całkowitą w jednej linii, która jest maksymalny wynik można uzyskać w końcu.

Ograniczenia:
T jest mniejsza niż 7.
D jest mniejsza niż 60001.
m i n mniej niż 8.

próbki wejściowe:

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

Sample Wyjście:

5911 
10832 
0 
11493 

próbowałem go, ale moje podejście działa bardzo wolno na 7x7 grid.I próbuję przejść każdą możliwą ścieżkę siatki rekurencyjnie i porównując sumę wszystkich path.Below jest mój kod

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

Proszę zasugerować, jak zoptymalizować to podejście lub lepszy algorytm.

+0

Powinny zostać przeniesione do przeglądu kodu, ponieważ kod działa? – tomdemuyt

+0

Kod @tomdemuyt działa, ale szukam optymalizacji w tym kodzie, ponieważ działa bardzo wolno dla dużych zestawów danych – archit

+0

To naprawdę nie jest przegląd kodu, ponieważ nie chodzi o to, jak lepiej zorganizować kod, ale o sprawny algorytm . – biziclop

Odpowiedz

1

Jedną z optymalizacji, o której myślę, jest zastosowanie Dijkstra's algorithm. Ten algorytm podaje minimalną (w twoim przypadku maksymalną) ścieżkę dla określonego węzła źródłowego do wszystkich węzłów docelowych.

W tym przykładzie pierwszym krokiem byłoby zbudowanie wykresu.

A ponieważ nie znasz węzła źródłowego, od którego należy zacząć, będziesz musiał zastosować algorytm Dijkstry dla każdego węzła w siatce. Złożoność czasu będzie lepsza niż metoda rekursji, ponieważ dla konkretnego węzła źródłowego, gdy znajduje się maksymalna ścieżka, algorytm Dijkstry nie przechodzi przez wszystkie możliwe ścieżki.

+1

Niestety, najdłuższa ścieżka jest problemem NP-zupełny, więc Dijkstra (który działa przy założeniu braku cykli o ujemnej masie) nie pomoże tutaj. Musisz wyprowadzić heurystyczną heurystyczną ścieżkę do Hamiltona. Ale bardziej wydajna niż wersja OP. – unkulunkulu

+0

W stwierdzeniu problemu wyraźnie stwierdza się, że w każdej komórce siatki występują nieujemne liczby całkowite. – user1168577

+0

Ale Dijkstra znajduje również najkrótsze ścieżki, aby go znaleźć najdłużej będziesz musiał negować wszystkie wagi ... – unkulunkulu

2

Zgodnie z sugestią , istnieją dokładne algorytmy, które szybko rozwiązują to zadanie. Ale trudno go znaleźć. I najprawdopodobniej są skomplikowane.

Jeśli chodzi o optymalizację podejścia OP, istnieje kilka możliwości.

Łatwiej jest zacząć od prostej mikrooptymalizacji: warunek Visit[row][col] == 1 jest zadowolony z najwyższego prawdopodobieństwa, więc powinien być na pierwszym miejscu.

Rozsądne jest również zoptymalizowanie algorytmu rozgałęzień i wiązań za pomocą programowania dynamicznego, aby uniknąć powtarzających się obliczeń. Zapamiętywanie wyników obliczeń w prostej tabeli mieszania dla przypadków nawet 19 odwiedzonych komórek poprawia wydajność o więcej niż 25% (a więcej można się spodziewać w przypadku niektórych poprawionych tabel mieszania). Poniżej znajduje się zmodyfikowany fragment kodu:

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

O wiele więcej ulepszeń można uzyskać, przetwarzając wstępnie matrycę wejściową. Jeśli w macierzy nie ma zer, lub w narożniku jest tylko jedno zero, można po prostu zsumować wszystkie wartości.

Jeśli istnieje tylko jedna wartość zero (nie w rogu), co najwyżej jedna niezerowa wartość powinna zostać wykluczona z sumy. Jeśli wymyślisz algorytm, który określa podzbiór komórek, z których jedna z komórek musi zostać usunięta, możesz po prostu wybrać najmniejszą wartość z tego podzestawu.

Jeśli występują dwie lub więcej wartości zerowych, użyj algorytmu odgałęzienia i powiązania: w tym przypadku jest to około 20 razy szybciej, ponieważ każda wartość zerowa w macierzy wejściowej oznacza około pięciokrotne zwiększenie prędkości.

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; 
} 
Powiązane problemy