Bu satır veya sütun 0 içeriyorsa, matristeki her hücreyi 0 olarak ayarlayın


152

0s ve 1s olan bir NxN matrisi verildi. A içeren her satırı 0tüm 0s'ye ve a içeren her sütunu 0tüm 0s'ye ayarlayın.

Örneğin

1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1
1 1 1 1 1

sonuç

0 0 0 0 0
0 0 0 0 0
0 0 1 1 0
0 0 0 0 0
0 0 1 1 0

Bir Microsoft Engineer bana fazladan bellek, sadece iki boole değişkeni ve bir geçiş içeren bir çözüm olduğunu söyledi, bu yüzden bu cevabı arıyorum.

BTW, biraz matris olduğunu düşünün, bu nedenle sadece 1s ve 0'ların matriste olmasına izin verilir.


1
Ha? "Ne zaman karşılaşırsan" nedir? Matristeki elementlerle hangi sırada karşılaşıyorsunuz? Ve tüm bitlerle karşılaşırsanız, yine de 0'ların hepsini alamazsınız?
ShreevatsaR

Elemanlar ile karşılaşmaya karar verdiğiniz sıra sizin kararınızdır, mesele şu ki, sadece uygun unsurları 0 olarak ayarlamanız gerekir. 0 olarak ayarlanmış tüm bitlerle karşılaşırsanız, evet matris yine sıfırlarla dolu olacaktır.
jaircazarin-old-account

"Uygun unsurlar" nelerdir? Biri "kaynak" matrisi ve diğeri "hedef" matrisi olmak üzere iki matris veriliyor ve "hedef" matrisi elde etmek için hangi sırayla "karşılaşacağınız" kararını vermelisiniz?
ShreevatsaR

1
Sanırım '1 geçiş' düşüncesi için bir şeyler karıştırdınız. Ekstra bellek olmadan, sadece 2 boolean ;-) 2 geçişte doğrusal olarak yapılabilir ;-) Bu yüzden demek istediğini çözüm olduğunu varsayıyorum (aşağıya bakınız)
Piotr Lesnicki

1
Sorun açıklaması gerçekten doğru ise arkadaşınızla iki kez kontrol edebilir misiniz? Bunu Hamming kodları veya parite bitleri ile yapabileceğimi sanıyordum, ancak şu ana kadar hiç başaramadım ve sorun kafama sabitlenmeye devam ediyor. :)
csl

Yanıtlar:


96

Tamam, bu yüzden burada 03:00 olduğu için yorgunum, ama ilk önce matrisin her sayısında tam olarak 2 geçişle denemem var, bu yüzden O (NxN) ve matrisin boyutunda lineer.

Ben sadece 1 ile satır / sütun nerede olduğunu bilmek için işaretleri olarak ilk sütun ve ilk satır kullanın. Sonra, ilk satır / sütun 1'in de olup olmadığını hatırlamak için l ve c değişkenleri vardır. Böylece ilk geçiş işaretleyicileri ayarlar ve gerisini 0'lara sıfırlar.

İkinci geçiş, 1 olarak işaretlenmiş yerlerin ve sütunların bulunduğu yerlerde 1'i ayarlar ve l ve c'ye bağlı olarak 1. satırı / sütunu sıfırlar.

Başlangıçta kareler sonunda karelere bağlı olduğu için 1 geçişte yapılabileceğimden şüpheliyim. Belki 2. geçişim daha verimli hale getirilebilir ...

import pprint

m = [[1, 0, 1, 1, 0],
     [0, 1, 1, 1, 0],
     [1, 1, 1, 1, 1],
     [1, 0, 1, 1, 1],
     [1, 1, 1, 1, 1]]



N = len(m)

### pass 1

# 1 rst line/column
c = 1
for i in range(N):
    c &= m[i][0]

l = 1
for i in range(1,N):
    l &= m[0][i]


# other line/cols
# use line1, col1 to keep only those with 1
for i in range(1,N):
    for j in range(1,N):
        if m[i][j] == 0:
            m[0][j] = 0
            m[i][0] = 0
        else:
            m[i][j] = 0

### pass 2

# if line1 and col1 are ones: it is 1
for i in range(1,N):
    for j in range(1,N):
        if m[i][0] & m[0][j]:
            m[i][j] = 1

# 1rst row and col: reset if 0
if l == 0:
    for i in range(N):
        m [i][0] = 0

if c == 0:
    for j in range(1,N):
        m [0][j] = 0


pprint.pprint(m)

Buradaki bir problem n> sizeof (c) ise bozulur. Bunu genel n durumunda çalışacak şekilde genişletmek için, problemin verdiği kısıtlamayı ihlal edeceğini düşündüğüm bit alanınızı dinamik olarak boyutlandırmanız gerekir.
Adam

Hayır, c bir bit alanı değil, sadece bir bool. & = Bitsel bir op değil (iyi, ama 1 bitlik bir değerde), c oradadır çünkü c, ilk sütunun 1 (true) olup olmadığını veya 0 (false) içerip içermediğini söyler.
Steve Jessop

2
Üst sıra [0,1,1,1 ...] ise başarısız olur Hata
düzeltm

Gerçekten (1, N) aralığında i için l = 1: l & = m [0] [i] (N) aralığında i için l = 1 olmalıdır: l & = m [0] [i]
Kristof Neirynck

1
BTW, ikinci geçişteki durumun şöyle olması gerektiğine inanıyorum: if m [i] [0] | m [0] [j]:
jaircazarin-old-account

16

Bu, bir geçişte yapılamaz çünkü tek bir bit, herhangi bir siparişte önce ve sonra bitler üzerinde bir etkiye sahiptir. IOW Diziyi geçtiğiniz sırada ne olursa olsun, daha sonra 0'a gelebilirsiniz, bu da geri dönüp önceki 1'i 0'a değiştirmeniz gerektiği anlamına gelir.

Güncelleme

İnsanlar, N'yi sabit bir değerle (8 diyelim) kısıtlayarak bunun bir geçiş olduğunu çözebileceğini düşünüyorlar. Bu a) noktayı kaçırıyor ve b) asıl soru değil. Sıralama hakkında bir soru yayınlamam ve "sadece 8 şeyi sıralamak istediğinizi varsayarak" başlayan bir cevap beklemem.

Bununla birlikte, N'nin aslında 8 ile sınırlı olduğunu biliyorsanız, makul bir yaklaşımdır. Yukarıdaki cevabım, böyle bir geri çekilme olmayan orijinal soruyu cevaplıyor.


Ek bellek olmadan bir geçişte yapılamaz. Sonuçları depolamak için başka bir NxN matrisi varsa bir geçişte yapılabilir. Aynı şekilde, bazı bit twiddles ve iki geçiş ile ek bellek olmadan yapılabilir.
paxos1977

2
Geçici bir matris kullansanız bile hala tek geçişte yapamazsınız, yoksa buraya gelmediğim garip bir şey var. Satır / sütun bilgilerini çıkarmak için bir geçişe ve her şeyi ayarlamak için bir geçişe ihtiyacınız vardır.
Lasse V. Karlsen

Bu sorunu, satır başına yalnızca bir benzersiz sıfır olmayan değer olduğunu fark ederek ve sadece referans olarak atayarak çözdüm.
Daniel Papasian

@ceretullis, lassevk: Hala tek geçişte yapılamayacağını düşünüyorum. Bu ikinci matrisin üzerindeki geçişlerin sayılması gerekir - aksi takdirde matrisi bir geçişte kopyalayabilir ve istediğiniz şekilde kopyayla çalışabilirsiniz. @Daniel Papasian: Çözümünüz int / long / neyse N> #bits'i ölçeklemiyor
Draemon

Draemon, teknik iyi ölçekleniyor, sadece matematik - bunu yapan bir donanım oluşturabilir veya kelime boyutunuzdan daha büyük sayıları değiştirmek için yazılım tekniklerini kullanabilirsiniz. İkisi de sorunun kısıtlamalarını ihlal
etmiyor

10

Benim fikrim, karşılık gelen sütun / satırdaki tüm değerlerin 1s olup olmadığını göstermek için son satır / sütundaki değerleri bayrak olarak kullanmaktır.

Tüm matris boyunca bir Zig Zag taraması kullanma Son satır / sütun DIŞINDA. Her öğede, son satır / sütundaki değeri, geçerli öğedeki değerle kendisinin mantıksal VE'sine göre ayarlarsınız. Başka bir deyişle, 0'a basarsanız, son satır / sütun 0 olarak ayarlanır. 1 ise, son satır / sütundaki değer yalnızca 1 ise, 1 olacaktır. Her durumda, geçerli öğeyi 0 olarak ayarlayın.

İşiniz bittiğinde, karşılık gelen sütun / satır 1s ile doldurulmuşsa, son satır / sütununuz 1s olmalıdır.

Son satır ve sütun boyunca doğrusal bir tarama yapın ve 1 sn. 1s'yi, son satırın ve sütunun her ikisi de 1s olduğu matris gövdesindeki karşılık gelen öğelerde ayarlayın.

Kodlama, tek tek hataları vb. Önlemek için zor olacaktır, ancak tek geçişte çalışması gerekir.


Çok güzel ... Aynı satırları düşünüyordum, ancak bu bilgiyi saklamak için son satırı / sütunu kullanarak kaçırdım, bu yüzden bir çift Nx1 dizisi için fazladan bellekle sıkışmıştım.
Dave Sherohman

1
Bu bana iki geçişe benziyor - bir geçiş zig-zag taraması, ikincisi "son satırın ve sütunun her ikisi de 1s olduğu matris gövdesindeki karşılık gelen öğelerde Set 1s" dir.
Adam Rosenfield

Zig-zag taraması (birisinin bana işaret ettiği gibi kesinlikle gerekli değildir) tüm AMA son satırı / sütunu geçer. Bu nedenle, son / satır sütununu taramak, daha önce taranan öğeleri çoğaltmaz. Dolayısıyla bir geçiş. Başka bir deyişle, bir N * N matrisi için O (N ^ 2).
Alastair

6

Burada bir çözüm var, tek bir geçişte çalışır ve ekstra bellek olmadan (yerinde büyümek için tasarruf) tüm işleme "yerinde" yapar.

Elbette diğer satırlar ve sütunlar için matrisi yok edecek olan sıfırların yazılmasını geciktirmek için özyineleme kullanır:

#include <iostream>

/**
* The idea with my algorithm is to delay the writing of zeros
* till all rows and cols can be processed. I do this using
* recursion:
* 1) Enter Recursive Function:
* 2) Check the row and col of this "corner" for zeros and store the results in bools
* 3) Send recursive function to the next corner
* 4) When the recursive function returns, use the data we stored in step 2
*       to zero the the row and col conditionally
*
* The corners I talk about are just how I ensure I hit all the row's a cols,
* I progress through the matrix from (0,0) to (1,1) to (2,2) and on to (n,n).
*
* For simplicities sake, I use ints instead of individual bits. But I never store
* anything but 0 or 1 so it's still fair ;)
*/

// ================================
// Using globals just to keep function
// call syntax as straight forward as possible
int n = 5;
int m[5][5] = {
                { 1, 0, 1, 1, 0 },
                { 0, 1, 1, 1, 0 },
                { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1 }
            };
// ================================

// Just declaring the function prototypes
void processMatrix();
void processCorner( int cornerIndex );
bool checkRow( int rowIndex );
bool checkCol( int colIndex );
void zeroRow( int rowIndex );
void zeroCol( int colIndex );
void printMatrix();

// This function primes the pump
void processMatrix() {
    processCorner( 0 );
}

// Step 1) This is the heart of my recursive algorithm
void processCorner( int cornerIndex ) {
    // Step 2) Do the logic processing here and store the results
    bool rowZero = checkRow( cornerIndex );
    bool colZero = checkCol( cornerIndex );

    // Step 3) Now progress through the matrix
    int nextCorner = cornerIndex + 1;
    if( nextCorner < n )
        processCorner( nextCorner );

    // Step 4) Finially apply the changes determined earlier
    if( colZero )
        zeroCol( cornerIndex );
    if( rowZero )
        zeroRow( cornerIndex );
}

// This function returns whether or not the row contains a zero
bool checkRow( int rowIndex ) {
    bool zero = false;
    for( int i=0; i<n && !zero; ++i ) {
        if( m[ rowIndex ][ i ] == 0 )
            zero = true;
    }
    return zero;
}

// This is just a helper function for zeroing a row
void zeroRow( int rowIndex ) {
    for( int i=0; i<n; ++i ) {
        m[ rowIndex ][ i ] = 0;
    }
}

// This function returns whether or not the col contains a zero
bool checkCol( int colIndex ) {
    bool zero = false;
    for( int i=0; i<n && !zero; ++i ) {
        if( m[ i ][ colIndex ] == 0 )
            zero = true;
    }

    return zero;
}

// This is just a helper function for zeroing a col
void zeroCol( int colIndex ) {
    for( int i=0; i<n; ++i ) {
        m[ i ][ colIndex ] = 0;
    }
}

// Just a helper function for printing our matrix to std::out
void printMatrix() {
    std::cout << std::endl;
    for( int y=0; y<n; ++y ) {
        for( int x=0; x<n; ++x ) {
            std::cout << m[y][x] << " ";
        }
        std::cout << std::endl;
    }
    std::cout << std::endl;
}

// Execute!
int main() {
    printMatrix();
    processMatrix();
    printMatrix();
}

2
Güzel bir çözüm, ancak teknik olarak, izin verilen iki booleandan daha fazla bellek kullanıyorsunuz (yığınta olmasına rağmen).
csl

1
Bu 1 pastan fazla. CheckRow ve checkCol öğelerinde erişildikçe (rowIndex, i) ve (i, colIndex) yazdırırsanız, her öğeye birden çok kez erişildiğini görürsünüz.
Draemon

Draemon: Haklısın, bence bilmeceden "tek geçiş" in açık bir tanımına ihtiyacımız var. Gerçekten de her bir öğeye sadece bir kez erişilebileceği anlamına geliyorsa, farklı bir çözüme ihtiyacımız var.
Adam

Orijinal sorunun (telefon oyunu aracılığıyla bize gelen), sorunun "yerinde" çözülmesi gerektiği anlamına geldiğini hayal ediyorum, yani matrisin başka bir kopyası yok. Ve daha optimum çözümlerin işleme için depolama gibi geçici takas () gerektirmesi bile gerekmez.
Adam

Ayrıca, kısıtlamaların ortaya çıkan makine koduna atıfta bulunduğundan şüphe duyuyorum. Yani, sağladığım "kod" sadece 2 bools kullanır. Derleyicimin yaptığı optimizasyonlara bağlı olarak, tüm lanet şey satır içi veya başka neler bilebilir. Benim çözümümün doğru olduğunu düşünüyorum;)
Adam

4

Bunun yapılabilir olduğunu sanmıyorum. İlk karede olduğunuzda ve değeri 1 olduğunda, aynı satır ve sütundaki diğer karelerin değerlerinin ne olduğunu bilmenin bir yolu yoktur. Yani bunları kontrol etmelisiniz ve sıfır varsa, ilk kareye dönün ve değerini sıfıra değiştirin. Bunu iki geçişte yapmanızı tavsiye ederim - ilk geçiş hangi satırların ve sütunların sıfırlanması gerektiği hakkında bilgi toplar (bilgi bir dizide saklanır, bu yüzden bazı ekstra bellek kullanıyoruz). İkinci geçiş değerleri değiştirir. Bunun aradığınız çözüm olmadığını biliyorum, ama bence pratik bir çözüm. Tarafınızdan verilen kısıtlamalar sorunu çözümsüz kılmaktadır.


Ek diziler olmadan neredeyse aynı çözüme sahibim (aşağıya bakın). ve doğrusal bir zamandır (ama 2 tane geçer)
Piotr Lesnicki

@Piotr: Evet, ikinci geçiş kaçınılmaz görünüyor. Önerdiğim satır ve sütun bilgilerini saklamak için dizilerin sunulması, daha az kontrol ve değer değiştirme olduğu için algoritmayı daha basit ve biraz daha hızlı hale getirir. Depolama ve verimlilik arasında bir değiş tokuş.
Boyan

3

Bunu iki tamsayı değişkeni ve iki geçişle yapabilirim (32 satıra ve sütuna kadar ...)

bool matrix[5][5] = 
{ 
    {1, 0, 1, 1, 0},
    {0, 1, 1, 1, 0},
    {1, 1, 1, 1, 1},
    {1, 0, 1, 1, 1},
    {1, 1, 1, 1, 1}
};

int CompleteRows = ~0;
int CompleteCols = ~0;

// Find the first 0
for (int row = 0; row < 5; ++row)
{
    for (int col = 0; col < 5; ++col)
    {
        CompleteRows &= ~(!matrix[row][col] << row);
        CompleteCols &= ~(!matrix[row][col] << col);
    }
}

for (int row = 0; row < 5; ++row)
    for (int col = 0; col < 5; ++col)
        matrix[row][col] = (CompleteRows & (1 << row)) && (CompleteCols & (1 << col));

Bu C # mı? ~ Ne anlama geliyor?
sker

Bu C ++. ~bir değişkendeki tüm bitleri tersine çevirir. 0x00000000, 0x00000000 olur. Temelde hepsi ile başlar ve bir 0 bulduğumda bir satır / sütun için bit temizlemek. CompleteCols bit 2 ve 3 kümesi vardır ve CompleteRows bit 2 ve 4 kümesi (0 tabanlı) vardır.
Eclipse

Ardından, matristeki bitleri, hem CompleteCols hem de CompleteRows'daki bir bite karşılık gelir.
Eclipse

3

problem tek geçişte çözülebilir

matrisi bir i X j dizisine kaydetmek.

1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
1 0 1 1 1 
1 1 1 1 1

one each pass save the values of i and j for an element which is 0 in arrays a and b
when first row is scanned a= 1 b = 2,5
when second row is scanned a=1,2 b= 1,2,5
when third row is scanned no change
when fourth row is scanned a= 1,2,4 and b= 1,2,5
when fifth row is scanned no change .

şimdi a ve b'ye kaydedilen i ve j değerleri için tüm değerleri 0 olarak yazdırın. kalan değerler 1 yani (3,3) (3,4) (5,3) ve (5,4)


1

İki geçiş alan bir başka çözüm, AND'leri yatay ve dikey olarak biriktirmektir:

1 0 1 1 0 | 0
0 1 1 1 0 | 0
1 1 1 1 1 | 1
1 0 1 1 1 | 0
1 1 1 1 1 | 1
----------+
0 0 1 1 0    

Eşlik bitleri , Hamming kodları veya dinamik programlama kullanarak böyle bir algoritma tasarlayabileceğimi düşündüm , muhtemelen bu iki boolean'ı 2 bit sayı olarak kullanıyordum, ancak henüz başarılı olamadım.

Sorun bildirimini mühendisinizle tekrar kontrol edebilir ve bize bildirir misiniz? Orada ise ise gerçekten çözüm, ben probleme yontmak devam etmek istiyorum.


1

Tüm AND satırlarının birlikte ne olduğunu takip etmek için tek bir değişken tutun.

Bir satır -1 ise (tüm 1'ler), sonraki satırı bu değişkene başvuru yapın

Bir satır başka bir şey değilse, 0'dır. Her şeyi tek geçişte yapabilirsiniz. Psuedo kodu:

foreach (my $row) rows {
     $andproduct = $andproduct & $row;
     if($row != -1) {
        zero out the row
     }  else {
        replace row with a reference to andproduct
     }
}

Bunu tek bir geçişte yapmalı - ama burada N'nin CPU'nun tek bir satırda aritmetik yapması için yeterince küçük olduğu varsayımı var, aksi takdirde her satırın üzerinde olup olmadığını belirlemek için her satırın üzerinden geçmeniz gerekecek 1s ya da değil, inanıyorum. Ama algos hakkında soruyor ve donanımımı kısıtlamıyorsan, cevabımı "N-bit aritmetiği destekleyen bir CPU inşa et ..."

C'de nasıl yapılabileceğine dair bir örnek: Not: Birlikte alınan değerlerin ve dizinin diziyi temsil ettiğini ve p ve numproduct'ın yinelemem olduğunu ve AND ürün değişkenlerinin sorunu uygulamak için kullandığını iddia ediyorum. (Çalışmamı doğrulamak için işaretçi aritmetiği ile arr üzerinde döngü yapmış olabilirdim, ama bir kez yeterliydi!)

int main() {
    int values[] = { -10, 14, -1, -9, -1 }; /* From the problem spec, converted to decimal for my sanity */
    int *arr[5] = { values, values+1, values+2, values+3, values+4 };
    int **p;
    int numproduct = 127;

    for(p = arr; p < arr+5; ++p) {
        numproduct = numproduct & **p;
        if(**p != -1) {
            **p = 0;
        } else {
            *p = &numproduct;
        }
    }

    /* Print our array, this loop is just for show */
    int i;
    for(i = 0; i < 5; ++i) {
        printf("%x\n",*arr[i]);
    }
    return 0;
}

Bu, verilen girişlerin sonucu olan 0, 0, 6, 0, 6 üretir.

Veya PHP'de, insanlar C'deki yığın oyunumun hile yaptığını düşünürse (Matrisin hangi şekilde olursa olsun saklayabilmem gerektiğinden, bunun olmadığını öneririm):

<?php

$values = array(-10, 14, -1, -9, -1);
$numproduct = 127;

for($i = 0; $i < 5; ++$i) {
    $numproduct = $numproduct & $values[$i];
    if($values[$i] != -1) {
        $values[$i] = 0;
    } else {
        $values[$i] = &$numproduct;
    }
}

print_r($values);

Bir şey mi kaçırıyorum?


N bir int / long / her neyse bit sayısından daha büyükse bu işe yaramaz, bu yüzden önemli olduğunu düşünmüyorum.
Draemon

0'lar dizinin altındaysa da bir şey yakalamaz ([] = {-1, -9, -1, 14, -10} değerleriyle deneyin).
Tutulma

Draemon, cevabımda, sorunun bir parçası olarak donanım kısıtlamaları olmadan, "N-bit aritmetiği destekleyen bir CPU oluşturun" ile başladığınızı belirtiyorum.
Daniel Papasian

Josh, takip etmiyorum. C veya PHP çözümü ve önerdiğiniz dizi ile, ben doğru cevap olduğuna inanıyorum 6 0 6 0 0 olsun.
Daniel Papasian

@Daniel - Yapamazsınız, çünkü N sabit değil. Ayrıca "1Mbit kelimeleri ile yeni bir bilgisayar inşa etmek neredeyse makul bir algoritmik adımdır.
Draemon

1

Güzel meydan okuma. Bu çözüm, yığın üzerinde oluşturulan sadece iki boolean kullanır, ancak işlev özyinelemeli olduğundan booleans yığın üzerinde birkaç kez oluşturulur.

typedef unsigned short     WORD;
typedef unsigned char      BOOL;
#define true  1
#define false 0
BYTE buffer[5][5] = {
1, 0, 1, 1, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
1, 0, 1, 1, 1,
1, 1, 1, 1, 1
};
int scan_to_end(BOOL *h,BOOL *w,WORD N,WORD pos_N)
{
    WORD i;
    for(i=0;i<N;i++)
    {
        if(!buffer[i][pos_N])
            *h=false;
        if(!buffer[pos_N][i])
            *w=false;
    }
    return 0;
}
int set_line(BOOL h,BOOL w,WORD N,WORD pos_N)
{
    WORD i;
    if(!h)
        for(i=0;i<N;i++)
            buffer[i][pos_N] = false;
    if(!w)
        for(i=0;i<N;i++)
            buffer[pos_N][i] = false;
    return 0;
}
int scan(int N,int pos_N)
{
    BOOL h = true;
    BOOL w = true;
    if(pos_N == N)
        return 0;
    // Do single scan
    scan_to_end(&h,&w,N,pos_N);
    // Scan all recursive before changeing data
    scan(N,pos_N+1);
    // Set the result of the scan
    set_line(h,w,N,pos_N);
    return 0;
}
int main(void)
{
    printf("Old matrix\n");
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[0][0],(WORD)buffer[0][1],(WORD)buffer[0][2],(WORD)buffer[0][3],(WORD)buffer[0][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[1][0],(WORD)buffer[1][1],(WORD)buffer[1][2],(WORD)buffer[1][3],(WORD)buffer[1][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[2][0],(WORD)buffer[2][1],(WORD)buffer[2][2],(WORD)buffer[2][3],(WORD)buffer[2][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[3][0],(WORD)buffer[3][1],(WORD)buffer[3][2],(WORD)buffer[3][3],(WORD)buffer[3][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[4][0],(WORD)buffer[4][1],(WORD)buffer[4][2],(WORD)buffer[4][3],(WORD)buffer[4][4]);
    scan(5,0);
    printf("New matrix\n");
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[0][0],(WORD)buffer[0][1],(WORD)buffer[0][2],(WORD)buffer[0][3],(WORD)buffer[0][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[1][0],(WORD)buffer[1][1],(WORD)buffer[1][2],(WORD)buffer[1][3],(WORD)buffer[1][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[2][0],(WORD)buffer[2][1],(WORD)buffer[2][2],(WORD)buffer[2][3],(WORD)buffer[2][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[3][0],(WORD)buffer[3][1],(WORD)buffer[3][2],(WORD)buffer[3][3],(WORD)buffer[3][4]);
    printf( "%d,%d,%d,%d,%d \n", (WORD)buffer[4][0],(WORD)buffer[4][1],(WORD)buffer[4][2],(WORD)buffer[4][3],(WORD)buffer[4][4]);
    system( "pause" );
    return 0;
}

Bu, aşağıdaki gibi bir desende tarar:

s,s,s,s,s
s,0,0,0,0
s,0,0,0,0
s,0,0,0,0
s,0,0,0,0


0,s,0,0,0
s,s,s,s,s
0,s,0,0,0
0,s,0,0,0
0,s,0,0,0

ve bunun gibi

Ve daha sonra, tarama işlevlerinin her birinin geri dönüşünde bu modeldeki değerleri değiştirmek. (Altüst):

0,0,0,0,c
0,0,0,0,c
0,0,0,0,c
0,0,0,0,c
c,c,c,c,c


0,0,0,c,0
0,0,0,c,0
0,0,0,c,0
c,c,c,c,c
0,0,0,c,0

ve bunun gibi


Sanırım bu doğru değil, çünkü yığınızda hala ikiden fazla boole kullanıyorsunuz.
csl

Üzgün ​​iki tür boolean gibi. Bu, sağladığı özelliklere en yakın şey. Burada gerçek bir çözüm görmek isterim. Mümkünse.
eaanon01

Gereksinimlerin yığını büyütmeye atıfta bulunduğunu sanmıyorum. Bence bu kesinlikle geçerli bir çözüm.
Adam

Bu da benim düşüncem. Ama başka biri daha iyi bir çözüm paylaşana kadar emin olamıyorum. En azından benim çözümüm derlenebilir ve herkes tarafından doğrulanabilir. :) ... Ben pratik sorunlar için psudo kodu bulunamadı. Thnx
eaanon01

1

Tamam bu bir çözüm

  • çalışma depolama için yalnızca bir ekstra uzun değer kullanır.
  • özyineleme kullanmaz.
  • sadece N'nin bir geçişi, N * N bile değil.
  • diğer N değerleri için çalışır ancak yeni # tanımlara ihtiyaç duyar.
#include <stdio.h>
#define BIT30 (1<<24)
#define COLMASK 0x108421L
#define ROWMASK 0x1fL
unsigned long long STARTGRID = 
((0x10 | 0x0 | 0x4 | 0x2 | 0x0) << 20) |
((0x00 | 0x8 | 0x4 | 0x2 | 0x0) << 15) |
((0x10 | 0x8 | 0x4 | 0x2 | 0x1) << 10) |
((0x10 | 0x0 | 0x4 | 0x2 | 0x1) << 5) |
((0x10 | 0x8 | 0x4 | 0x2 | 0x1) << 0);


void dumpGrid (char* comment, unsigned long long theGrid) {
    char buffer[1000];
    buffer[0]='\0';
    printf ("\n\n%s\n",comment);
    for (int j=1;j<31; j++) {
        if (j%5!=1)
            printf( "%s%s", ((theGrid & BIT30)==BIT30)? "1" : "0",(((j%5)==0)?"\n" : ",") );    
        theGrid = theGrid << 1;
    }
}

int main (int argc, const char * argv[]) {
    unsigned long long rowgrid = STARTGRID;
    unsigned long long colGrid = rowgrid;

    unsigned long long rowmask = ROWMASK;
    unsigned long long colmask = COLMASK;

    dumpGrid("Initial Grid", rowgrid);
    for (int i=0; i<5; i++) {
        if ((rowgrid & rowmask)== rowmask) rowgrid |= rowmask;
        else rowgrid &= ~rowmask;
        if ((colGrid & colmask) == colmask) colmask |= colmask;
        else colGrid &=  ~colmask;
        rowmask <<= 5;
        colmask <<= 1;
    }
    colGrid &= rowgrid;
    dumpGrid("RESULT Grid", colGrid);
    return 0;
    }

Emin olmak için güzel bir çözüm. Herhalde buradaki çözüm, gereksinimlerden en az birini ihmal ediyor. Dolayısıyla, N için izin verilen maksimum değere sahip bir çözüme sahip olmak dünyadaki en kötü şey değil, bu konuda güzel bir iş :)
Adam

N'den 8'e sınırlama ve bunun tek geçiş şartını karşıladığını iddia etmek sadece aptalca. Bu genel bir çözüm değil. Soruda N boyutunda herhangi bir kısıtlama belirtilmedi, bu yüzden sadece bir alt sorunu çözdünüz.
Draemon

ancak tüm bu çözümlerin N üzerinde bir şekilde bir sınırı vardır.
AnthonyLambert

N'nin bir geçişi olduğunu söylemek tamamen yanlıştır. Orijinal matristeki her pozisyonun değerini okumak bile O (N ^ 2) 'dir ve çözümü hesaplayabilmek için her pozisyondaki değeri en az bir kez okumak kesinlikle gereklidir. Değerleri uzun bir süre içinde tek bit olarak saklasanız bile, O (N ^ 2) bitleri olduğu için her bite erişim O (N ^ 2) olacaktır.
Alderath

RowGrid değerinin tüm ızgarayı sakladığı açıktır ve 1. okumadan sonra, optimize edici herhangi bir şey varsa, tüm algoritmaya yönelik işlemci kayıtlarından biri olacaktır.
AnthonyLambert

1

Aslında. Sadece algoritmayı çalıştırmak ve sonuçları yazdırmak istiyorsanız (yani onları geri yüklemek istemiyorsanız, bu bir geçişte kolayca yapılabilir) Algoritmayı çalıştırırken diziyi değiştirmeye çalıştığınızda sorun gelir.

İşte benim çözümüm Sadece bir givein (i, j) öğesi için satır / sütun değerlerini ANDing ve yazdırmayı içerir.

#include <iostream>
#include "stdlib.h"

void process();

int dim = 5;
bool m[5][5]{{1,0,1,1,1},{0,1,1,0,1},{1,1,1,1,1},{1,1,1,1,1},{0,0,1,1,1}};


int main() {
    process();
    return 0;
}

void process() {
    for(int j = 0; j < dim; j++) {
        for(int i = 0; i < dim; i++) {
            std::cout << (
                          (m[0][j] & m[1][j] & m[2][j] & m[3][j] & m[4][j]) &
                          (m[i][0] & m[i][1] & m[i][2] & m[i][3] & m[i][4])
                          );
        }
        std::cout << std::endl;
    }
}

1

Bu sorunu C # 'da çözmeye çalıştım.

Gerçek matris dışında iki döngü değişkeni (i ve j) kullandım ve boyutunu temsil eden n

Denediğim mantık:

  1. Matrisin her eşmerkezli karesinde yer alan satırlar ve sütunlar için AND hesaplayın
  2. Köşe hücrelerinde saklayın (Saat yönünün tersine sakladım)
  3. Belirli bir kareyi değerlendirirken iki köşenin değerlerini korumak için iki bool değişkeni kullanılır.
  4. Dış döngü (i) orta yoldayken bu işlem sona erer.
  5. Köşe hücrelere dayalı diğer hücrelerin sonuçlarını değerlendirin (i'nin geri kalanı için). Bu işlem sırasında köşe hücrelerini atlayın.
  6. N'ye ulaştığında, köşe hücreleri hariç tüm hücrelerin sonucu olurdu.
  7. Köşe hücrelerini güncelleyin. Bu, problemde belirtilen tek geçiş kısıtlaması dışında n / 2 uzunluğuna ekstra bir iterasyondur.

Kod:

void Evaluate(bool [,] matrix, int n)
{
    bool tempvar1, tempvar2;

    for (var i = 0; i < n; i++)
    {
        tempvar1 = matrix[i, i];
        tempvar2 = matrix[n - i - 1, n - i - 1];

        var j = 0;

        for (j = 0; j < n; j++)
        {
            if ((i < n/2) || (((n % 2) == 1) && (i == n/2) && (j <= i)))
            {
                // store the row and col & results in corner cells of concentric squares
                tempvar1 &= matrix[j, i];
                matrix[i, i] &= matrix[i, j];
                tempvar2 &= matrix[n - j - 1, n - i - 1];
                matrix[n - i - 1, n - i - 1] &= matrix[n - i - 1, n - j - 1];
            }
            else
            {
                // skip corner cells of concentric squares
                if ((j == i) || (j == n - i - 1)) continue;

                // calculate the & values for rest of them
                matrix[i, j] = matrix[i, i] & matrix[n - j - 1, j];
                matrix[n - i - 1, j] = matrix[n - i - 1, n - i - 1] & matrix[n - j - 1, j];

                if ((i == n/2) && ((n % 2) == 1))
                {
                    // if n is odd
                    matrix[i, n - j - 1] = matrix[i, i] & matrix[j, n - j - 1];
                }
            }
        }

        if ((i < n/2) || (((n % 2) == 1) && (i <= n/2)))
        {
            // transfer the values from temp variables to appropriate corner cells of its corresponding square
            matrix[n - i - 1, i] = tempvar1;
            matrix[i, n - i - 1] = tempvar2;
        }
        else if (i == n - 1)
        {
            // update the values of corner cells of each concentric square
            for (j = n/2; j < n; j++)
            {
                tempvar1 = matrix[j, j];
                tempvar2 = matrix[n - j - 1, n - j - 1];

                matrix[j, j] &= matrix[n - j - 1, j];
                matrix[n - j - 1, j] &= tempvar2;

                matrix[n - j - 1, n - j - 1] &= matrix[j, n - j - 1];
                matrix[j, n - j - 1] &= tempvar1;
            }
        }
    }
}

1

Bir Geçiş - Ben girişi sadece bir kez geçtim ama yeni bir dizi ve sadece iki ekstra Boole değişkeni kullandım.

public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();

        boolean rowDel = false, colDel = false;
        int arr[][] = new int[n][n];
        int res[][] = new int[n][n];
        int i, j;
        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                arr[i][j] = sc.nextInt();
                res[i][j] = arr[i][j];  
            }
        }

        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                if (arr[i][j] == 0)
                    colDel = rowDel = true; //See if we have to delete the
                                            //current row and column
                if (rowDel == true){
                    res[i] = new int[n];
                    rowDel = false;
                }
                if(colDel == true){
                    for (int k = 0; k < n; k++) {
                        res[k][j] = 0;
                    }
                    colDel = false;
                }

            }

        }

        for (i = 0; i < n; i++) {

            for (j = 0; j < n; j++) {
                System.out.print(res[i][j]);
            }
            System.out.println();
        }
        sc.close();

    }

0

Kısıtlamalar göz önüne alındığında imkansız olsa da, bunu yapmanın en etkili alan matrisi üst üste binen, sıralı bir sütun / sütun biçiminde, zig-zag tarzında tuğla döşemeye benzer bir desen yapacak şekilde çevirmektir:

-----
|----
||---
|||--
||||-

Bunu kullanarak, belirtildiği gibi her satıra / sütuna gidersiniz ve herhangi bir zamanda 0 ile karşılaşırsanız, bir boolean değişkeni ayarlayın ve girişleri gittikçe 0 olarak ayarlayarak bu satırı / sütunu yeniden yürütün.

Bu, fazladan bellek gerektirmez ve yalnızca bir boolean değişkeni kullanır. Ne yazık ki, "uzak" kenar 0 olarak ayarlanmışsa, bu en kötü durumdur ve tüm diziyi iki kez yürürsünüz.


Yanılıyor olabilirim, ama bunun işe yaradığından emin misin? 3. sütunu yaparken, ilk satırdaki üst satırdaki değerin ilk satırı işlemeden önce 1 veya 0 olup olmadığını nasıl anlarsınız?
Steve Jessop

Bilmiyorsunuz, ama buna da ihtiyacınız yok. 0 ise, tüm sütunun 0 olması gerekir. Önceki satırdaki değer 1 ise, üstündeki tüm satırların 1 (ve her zaman öyleydi) olduğunu bilirsiniz.
Dave Sherohman

0

bir sonuç matrisi oluşturun ve tüm değerleri 1 olarak ayarlayın. 0 ile karşılaşıldığında veri matrisinden geçin, sonuç matrisi satır sütununu 0 olarak ayarlayın

İlk geçişin sonunda, sonuç matrisi doğru cevaba sahip olacaktır.

Oldukça basit görünüyor. Kaçırdığım bir hile var mı? Bir sonuç kümesi kullanmanıza izin verilmiyor mu?

DÜZENLE:

F # işlevine benziyor, ancak tek bir geçiş yapsanız bile, işlev yinelemeli olabileceğinden bu biraz hile yapıyor.

Görüşme yapan kişi işlevsel programlamayı biliyor musunuz diye anlamaya çalışıyor gibi görünüyor.


1
Sonuç kümesi kullanmak fazladan bellek gerektirir.
cdeszaq

İşlevsel programlama, orijinal diziyi yerinde değiştirmez.
Svante

0

4 bools ve 2 loop sayacı kullanarak tek geçişli, yerinde (özyinelemesiz) bir çözüm buldum. Ben 2 bools ve 2 ints azaltmak için başaramadım, ama mümkün olsaydı ben sürpriz olmaz. Her bir hücrenin 3 okuma ve 3 yazma işlemlerini yapar ve O (N ^ 2) yani olmalıdır. dizi boyutunda doğrusal.

Bunu çözmek için birkaç saatim oldu - bir röportaj baskısı altında olmak istemem! Bir booboo yapsaydım, onu görmek için çok yorgunum ...

Um ... "tek geçiş" i, her bir değere bir kez dokunmak yerine, matriste bir tarama yapmak olarak tanımlamayı seçiyorum! :-)

#include <stdio.h>
#include <memory.h>

#define SIZE    5

typedef unsigned char u8;

u8 g_Array[ SIZE ][ SIZE ];

void Dump()
{
    for ( int nRow = 0; nRow < SIZE; ++nRow )
    {
        for ( int nColumn = 0; nColumn < SIZE; ++nColumn )
        {
            printf( "%d ", g_Array[ nRow ][ nColumn ] );
        }
        printf( "\n" );
    }
}

void Process()
{
    u8 fCarriedAlpha = true;
    u8 fCarriedBeta = true;
    for ( int nStep = 0; nStep < SIZE; ++nStep )
    {
        u8 fAlpha = (nStep > 0) ? g_Array[ nStep-1 ][ nStep ] : true;
        u8 fBeta = (nStep > 0) ? g_Array[ nStep ][ nStep - 1 ] : true;
        fAlpha &= g_Array[ nStep ][ nStep ];
        fBeta &= g_Array[ nStep ][ nStep ];
        g_Array[ nStep-1 ][ nStep ] = fCarriedBeta;
        g_Array[ nStep ][ nStep-1 ] = fCarriedAlpha;
        for ( int nScan = nStep + 1; nScan < SIZE; ++nScan )
        {
            fBeta &= g_Array[ nStep ][ nScan ];
            if ( nStep > 0 )
            {
                g_Array[ nStep ][ nScan ] &= g_Array[ nStep-1 ][ nScan ];
                g_Array[ nStep-1][ nScan ] = fCarriedBeta;
            }

            fAlpha &= g_Array[ nScan ][ nStep ];
            if ( nStep > 0 )
            {
                g_Array[ nScan ][ nStep ] &= g_Array[ nScan ][ nStep-1 ];
                g_Array[ nScan ][ nStep-1] = fCarriedAlpha;
            }
        }

        g_Array[ nStep ][ nStep ] = fAlpha & fBeta;

        for ( int nScan = nStep - 1; nScan >= 0; --nScan )
        {
            g_Array[ nScan ][ nStep ] &= fAlpha;
            g_Array[ nStep ][ nScan ] &= fBeta;
        }
        fCarriedAlpha = fAlpha;
        fCarriedBeta = fBeta;
    }
}

int main()
{
    memset( g_Array, 1, sizeof(g_Array) );
    g_Array[0][1] = 0;
    g_Array[0][4] = 0;
    g_Array[1][0] = 0;
    g_Array[1][4] = 0;
    g_Array[3][1] = 0;

    printf( "Input:\n" );
    Dump();
    Process();
    printf( "\nOutput:\n" );
    Dump();

    return 0;
}

0

Umarım 1 geçişli c # çözümümden hoşlanırsınız

O (1) ile bir eleman alabilir ve sadece bir satır ve bir matris sütunu gerekir

bool[][] matrix =
{
    new[] { true, false, true, true, false }, // 10110
    new[] { false, true, true, true, false }, // 01110
    new[] { true, true, true, true, true },   // 11111
    new[] { true, false, true, true, true },  // 10111
    new[] { true, true, true, true, true }    // 11111
};

int n = matrix.Length;
bool[] enabledRows = new bool[n];
bool[] enabledColumns = new bool[n];

for (int i = 0; i < n; i++)
{
    enabledRows[i] = true;
    enabledColumns[i] = true;
}

for (int rowIndex = 0; rowIndex < n; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < n; columnIndex++)
    {
        bool element = matrix[rowIndex][columnIndex];
        enabledRows[rowIndex] &= element;
        enabledColumns[columnIndex] &= element;
    }
}

for (int rowIndex = 0; rowIndex < n; rowIndex++)
{
    for (int columnIndex = 0; columnIndex < n; columnIndex++)
    {
        bool element = enabledRows[rowIndex] & enabledColumns[columnIndex];
        Console.Write(Convert.ToInt32(element));
    }
    Console.WriteLine();
}

/*
    00000
    00000
    00110
    00000
    00110
*/

Tek sorun, bu işi yapmak için iki ekstra veri dizisi kullanıyor olabilirsiniz. Koşullardan biri fazladan bellek kullanmamaktır. Ama güzel olsa! Bu benim cevapta yaptığım temelde :)
Kenny Cason

0

1 geçiş, 2 boolean. Sadece yinelemelerde tamsayı dizinlerinin sayılmadığını varsaymak zorundayım.

Bu tam bir çözüm değil ama bu noktadan geçemiyorum.

Sadece 0'ın orijinal 0 mı yoksa 0'a dönüştürülmüş 1 mi olduğunu belirleyebilseydim -1'i kullanmak zorunda kalmazdım ve bu işe yarardı.

Benim çıktı şöyle:

-1  0 -1 -1  0
 0 -1 -1 -1  0
-1 -1  1  1 -1
-1  0 -1 -1 -1
-1 -1  1  1 -1

Yaklaşımımın özgünlüğü, değerleri ayarlamak için 0 ve son yarısı içerip içermediğini belirlemek için bir satır veya sütunun incelenmesinin ilk yarısını kullanmaktır - bu, x ve genişlik-x ve sonra y ve yüksekliğe bakarak yapılır -y her yinelemede. Yinelemenin ilk yarısının sonuçlarına dayanarak, satır veya sütunda 0 bulunursa, yinelemenin son yarısını 1'leri -1'lere değiştirmek için kullanırım.

Ben sadece bu sadece 1 boolean bırakarak 1 ile yapılabilir ...?

Birisinin "Ah, sadece bunu yap ..." diyebileceğini umarak gönderiyorum (Ve yayınlamamak için çok fazla zaman harcadım.)

İşte VB kodu:

Dim D(,) As Integer = {{1, 0, 1, 1, 1}, {0, 1, 1, 0, 1}, {1, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {0, 0, 1, 1, 1}}

Dim B1, B2 As Boolean

For y As Integer = 0 To UBound(D)

    B1 = True : B2 = True

    For x As Integer = 0 To UBound(D)

        // Scan row for 0's at x and width - x positions. Halfway through I'll konw if there's a 0 in this row.
        //If a 0 is found set my first boolean to false.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(x, y) = 0 Or D(UBound(D) - x, y) = 0 Then B1 = False
        End If

        //If the boolean is false then a 0 in this row was found. Spend the last half of this loop
        //updating the values. This is where I'm stuck. If I change a 1 to a 0 it will cause the column
        //scan to fail. So for now I change to a -1. If there was a way to change to 0 yet later tell if
        //the value had changed this would work.
        If Not B1 Then
            If x >= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
                If D(x, y) = 1 Then D(x, y) = -1
                If D(UBound(D) - x, y) = 1 Then D(UBound(D) - x, y) = -1
            End If
        End If

        //These 2 block do the same as the first 2 blocks but I switch x and y to do the column.
        If x <= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
            If D(y, x) = 0 Or D(y, UBound(D) - x) = 0 Then B2 = False
        End If

        If Not B2 Then
            If x >= (Math.Ceiling((UBound(D) + 1) / 2) - 1) Then
                If D(y, x) = 1 Then D(y, x) = -1
                If D(y, UBound(D) - x) = 1 Then D(y, UBound(D) - x) = -1
            End If
        End If

    Next
Next

0

Kimse ikili form kullanmıyor mu? çünkü sadece 1 ve 0'dır. İkili vektörleri kullanabiliriz.

def set1(M, N):
    '''Set 1/0s on M according to the rules.

    M is a list of N integers. Each integer represents a binary array, e.g.,
    000100'''
    ruler = 2**N-1
    for i,v in enumerate(M):
        ruler = ruler & M[i]
        M[i] = M[i] if M[i]==2**N-1 else 0  # set i-th row to all-0 if not all-1s
    for i,v in enumerate(M):
        if M[i]: M[i] = ruler
    return M

İşte test:

M = [ 0b10110,
      0b01110,
      0b11111,
      0b10111,
      0b11111 ]

print "Before..."
for i in M: print "{:0=5b}".format(i)

M = set1(M, len(M))
print "After..."
for i in M: print "{:0=5b}".format(i)

Ve çıktı:

Before...
10110
01110
11111
10111
11111
After...
00000
00000
00110
00000
00110

0

Bir geçiş, ancak bir giriş ve çıkış matrisi kullanmak için böyle bir şey yapabilirsiniz:

output(x,y) = col(xy) & row(xy) == 2^n

col(xy)noktayı içeren sütundaki bitler nerede xy; row(xy), noktayı içeren satırdaki bitlerdir xy. nmatrisin boyutudur.

Sonra sadece girişin üzerinden dönün. Daha fazla yer tasarrufu sağlayacak şekilde genişletilebilir mi?


0

Bir matris taraması, iki boolean, özyineleme yok.

İkinci geçişten nasıl kaçınılır? Sonunda sıfır belirdiğinde satırları veya sütunları temizlemek için ikinci geçiş gerekir.

Ancak bu sorun çözülebilir, çünkü #i satırını taradığımızda # i-1 satırının satır durumunu zaten biliyoruz. Yani, #i satırını tararken, gerekirse # i-1 satırını aynı anda temizleyebiliriz.

Aynı çözüm sütunlar için de çalışır, ancak veriler bir sonraki yineleme ile değiştirilmezken satırları ve sütunları aynı anda taramamız gerekir.

İlk satırın ve ilk sütunun durumunu saklamak için iki boole gerekir, çünkü değerleri algoritmanın ana bölümünün yürütülmesi sırasında değiştirilir.

Daha fazla boolean eklemekten kaçınmak için, matrisin ilk satırında ve sütununda satırlar ve sütunlar için "açık" bayrağı saklıyoruz.

public void Run()
{
    const int N = 5;

    int[,] m = new int[N, N] 
                {{ 1, 0, 1, 1, 0 },
                { 1, 1, 1, 1, 0 },
                { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 },
                { 1, 1, 1, 1, 1 }};

    bool keepFirstRow = (m[0, 0] == 1);
    bool keepFirstColumn = keepFirstRow;

    for (int i = 1; i < N; i++)
    {
        keepFirstRow = keepFirstRow && (m[0, i] == 1);
        keepFirstColumn = keepFirstColumn && (m[i, 0] == 1);
    }

    Print(m); // show initial setup

    m[0, 0] = 1; // to protect first row from clearing by "second pass"

    // "second pass" is performed over i-1 row/column, 
    // so we use one more index just to complete "second pass" over the 
    // last row/column
    for (int i = 1; i <= N; i++)
    {
        for (int j = 1; j <= N; j++)
        {
            // "first pass" - searcing for zeroes in row/column #i
            // when i = N || j == N it is additional pass for clearing 
            // the previous row/column
            // j >= i because cells with j < i may be already modified 
            // by "second pass" part
            if (i < N && j < N && j >= i) 
            {
                m[i, 0] &= m[i, j];
                m[0, j] &= m[i, j];

                m[0, i] &= m[j, i];
                m[j, 0] &= m[j, i];
            }

            // "second pass" - clearing the row/column scanned 
            // in the previous iteration
            if (m[i - 1, 0] == 0 && j < N)
            {
                m[i - 1, j] = 0;
            }

            if (m[0, i - 1] == 0 && j < N)
            {
                m[j, i - 1] = 0;
            }
        }

        Print(m);
    }

    // Clear first row/column if needed
    if (!keepFirstRow || !keepFirstColumn)
    {
        for (int i = 0; i < N; i++)
        {
            if (!keepFirstRow)
            {
                m[0, i] = 0;
            }
            if (!keepFirstColumn)
            {
                m[i, 0] = 0;
            }
        }
    }

    Print(m);

    Console.ReadLine();
}

private static void Print(int[,] m)
{
    for (int i = 0; i < m.GetLength(0); i++)
    {
        for (int j = 0; j < m.GetLength(1); j++)
        {
            Console.Write(" " + m[i, j]);
        }
        Console.WriteLine();
    }
    Console.WriteLine();
}

0

aşağıdaki gibi ek alan gereksinimi olmadan çalışır:

ilk önce satır öğelerinin çarpımının, öğenin bulunduğu satır öğelerinin çarpımının istenen değeri verdiğine dikkat edin.

Ek boşluk kullanmamak için (yeni bir matris oluşturup doldurmamak, bunun yerine doğrudan matrise değişiklikleri uygulamak için), matrisin sol üst köşesinden başlayın ve (0'da "başlayan" herhangi bir ixi matrisi için hesaplama yapın , 0)) herhangi bir indeksi olan herhangi bir öğeyi dikkate almadan önce> i.

umarım bu işe yarar (havent testet)


Yanlış gibi görünüyor. Satır 0'ın yalnızca 1 değeri olduğunu varsayın. (0,0) için ayarladığınız son değer 0 ise, daha sonra satırın tamamını 0 olarak ayarlayacaksınız, bu da doğru olmayabilir. Prensibinizi kullanarak dinamik programlama stili yapmak için aslında hücre başına 2 değer depolamanız gerekir.
Eyal Schneider

tabi, haklısın. İki değeri depolamak yerine, örneğin "eski" matristeki 1 olan ve sonunda 0 ile değiştirilecek olan hücreleri temsil eden üçüncü bir olasılık da kullanabilirim. Tabii ki, kişi mutlak almak zorunda çarpma işleminden sonraki değerler. Sonunda, -1'in tamamı 0'larla değiştirilir.
DFF

0

Bu edilir TEST C ++, farklı N, ve bir:
bir geçişte , İKİ bool değerlerden oluşan , Yinelemesiz , no ilave BELLEK , ARBITRARLY BÜYÜK N için de geçerlidir
(burada çözümlerden Şimdiye kadar hiçbiri bu TÜMÜNÜ yapın.)

Daha spesifik olarak, iki döngü sayacının iyi olduğunu eğlendiriyorum. Okunabilirlik için her seferinde hesaplanmak yerine var olan iki sabit imzasız var. Dış halkanın aralığı [0, N] ve iç halkanın aralığı [1, n - 1] 'dir. Switch deyimi döngüde çoğunlukla gerçekten sadece bir geçiş olduğunu çok açık bir şekilde göstermek için var.

Algoritma Stratejisi:

İlk hile bize matrisin içeriğini biriktirmek için matrisin kendisinden bir satır ve bir sütun, bu bellek ilk satır ve sütundan gerçekten bilmemiz gereken her şeyi iki boole içine yükleyerek kullanılabilir hale geliyor. İkinci püf noktası, alt matrisin simetrisini ve endekslerini kullanarak birinden iki geçiş elde etmektir.

Algoritma Konusu:

  • İlk satırı tarayın ve hepsi bir boole'de ise depolayın, sonucu ikinci bir boole'de saklayan ilk sütun için de aynısını yapın.
  • İlk satırı ve ilk sütunu hariç tutan alt matris için: paragraf okur gibi soldan sağa, yukarıdan aşağıya doğru yineleyin. Her bir öğeyi ziyaret ettikten sonra, alt matrisi tersine ziyaret ederseniz ziyaret edilecek ilgili öğeyi de ziyaret edin. Her eleman için AND değerini satırının ilk sütunu geçtiği yere ve AND değerini ise sütunun ilk satırı geçtiği yere doğru.
  • Alt matrisin merkezine ulaşıldığında, yukarıdaki gibi iki öğeyi aynı anda ziyaret etmeye devam edin. Ancak şimdi, ziyaret edilen öğelerin değerini, satırının ilk sütunu geçtiği ve sütununun ilk satırı geçtiği AND işaretini ayarlayın. Bundan sonra alt matris tamamlanır.
  • İlk satırı ve ilk sütunu doğru değerlerine ayarlamak için yalvarırken hesaplanan iki boole değişkenini kullanın.

Templatized C ++ Uygulaması:

template<unsigned n>
void SidewaysAndRowColumn(int((&m)[n])[n]) {
    bool fcol = m[0][0] ? true : false;
    bool frow = m[0][0] ? true : false;
    for (unsigned d = 0; d <= n; ++d) {
        for (unsigned i = 1; i < n; ++i) {
            switch (d) {
                case 0:
                    frow    = frow && m[d][i];
                    fcol    = fcol && m[i][d];
                    break;
                default:
                {
                    unsigned const rd = n - d;
                    unsigned const ri = n - i;
                    if (d * n + i < rd * n + ri)
                    {
                        m[ d][ 0] &= m[ d][ i];
                        m[ 0][ d] &= m[ i][ d];
                        m[ 0][ i] &= m[ d][ i];
                        m[ i][ 0] &= m[ i][ d];
                        m[rd][ 0] &= m[rd][ri];
                        m[ 0][rd] &= m[ri][rd];
                        m[ 0][ri] &= m[rd][ri];
                        m[ri][ 0] &= m[ri][rd];
                    }
                    else
                    {
                        m[ d][ i] = m[ d][0] & m[0][ i];
                        m[rd][ri] = m[rd][0] & m[0][ri];
                    }
                    break;
                }
                case n:
                    if (!frow)
                        m[0][i] = 0;
                    if (!fcol)
                        m[i][0] = 0;
            };
        }
    }
    m[0][0] = (frow && fcol) ? 1 : 0;
}

0

Tamam, bunun bir eşleşme olmadığını anlıyorum, ama bir geçişte iki bool yerine bir bool ve bir bayt kullanarak aldım ... kapat. Ben de bunun verimliliğine kefil olmazdım, ancak bu tür sorular genellikle optimal çözümlerden daha azını gerektirir.

private static void doIt(byte[,] matrix)
{
    byte zeroCols = 0;
    bool zeroRow = false;

    for (int row = 0; row <= matrix.GetUpperBound(0); row++)
    {
        zeroRow = false;
        for (int col = 0; col <= matrix.GetUpperBound(1); col++)
        {
            if (matrix[row, col] == 0)
            {

                zeroRow = true;
                zeroCols |= (byte)(Math.Pow(2, col));

                // reset this column in previous rows
                for (int innerRow = 0; innerRow < row; innerRow++)
                {
                    matrix[innerRow, col] = 0;
                }

                // reset the previous columns in this row
                for (int innerCol = 0; innerCol < col; innerCol++)
                {
                    matrix[row, innerCol] = 0;
                }
            }
            else if ((int)(zeroCols & ((byte)Math.Pow(2, col))) > 0)
            {
                matrix[row, col] = 0;
            }

            // Force the row to zero
            if (zeroRow) { matrix[row, col] = 0; }
        }
    }
}

0

Bunu bir geçişte yapabilirsiniz - eğer matrise rasgele erişim sırasına erişmeyi saymazsanız, ilk etapta tek geçiş yapmanın yararlarını ortadan kaldırır (önbellek tutarlılığı / bellek bant genişliği).

[değiştir: basit ama yanlış çözüm silindi]

İki geçişte tek geçiş yönteminden daha iyi performans elde etmelisiniz: biri satır / sütun bilgisi biriktirmek ve diğeri uygulamak için. Diziye (satır-büyük sırada) tutarlı bir şekilde erişilir; önbellek boyutunu aşan diziler için (ancak satırları önbelleğe sığabilecek), veriler bellekten iki kez okunmalı ve bir kez saklanmalıdır:

void fixmatrix2(int M[][], int rows, int cols) {
    bool clearZeroRow= false;
    bool clearZeroCol= false;
    for(int j=0; j < cols; ++j) {
        if( ! M[0][j] ) {
            clearZeroRow= true;
        }
    }
    for(int i=1; i < rows; ++i) { // scan/accumulate pass
        if( ! M[i][0] ) {
            clearZeroCol= true;
        }
        for(int j=1; j < cols; ++j) {
            if( ! M[i][j] ) {
                M[0][j]= 0;
                M[i][0]= 0;
            }
        }
    }
    for(int i=1; i < rows; ++i) { // update pass
        if( M[i][0] ) {
            for(int j=0; j < cols; ++j) {
                if( ! M[j][0] ) {
                    M[i][j]= 0;
                }
            }
        } else {
            for(int j=0; j < cols; ++j) {
                M[i][j]= 0;
            }
        }
        if(clearZeroCol) {
            M[i][0]= 0;
        }
    }
    if(clearZeroRow) {
        for(int j=0; j < cols; ++j) {
            M[0][j]= 0;
        }
    }
}

0

Düşünebildiğim en basit çözüm aşağıda yapıştırıldı. Mantık, yineleme sırasında hangi satır ve sütunun sıfır olarak ayarlanacağını kaydetmektir.

import java.util.HashSet;
import java.util.Set;

public class MatrixExamples {
    public static void zeroOut(int[][] myArray) {
        Set<Integer> rowsToZero = new HashSet<>();
        Set<Integer> columnsToZero = new HashSet<>();

        for (int i = 0; i < myArray.length; i++) { 
            for (int j = 0; j < myArray.length; j++) {
                if (myArray[i][j] == 0) {
                    rowsToZero.add(i);
                    columnsToZero.add(j);
                }
            }
        }

        for (int i : rowsToZero) {
            for (int j = 0; j < myArray.length; j++) {
                myArray[i][j] = 0;
            }
        }

        for (int i : columnsToZero) {
            for (int j = 0; j < myArray.length; j++) {
                myArray[j][i] = 0;
            }
        }

        for (int i = 0; i < myArray.length; i++) { // record which rows and                                             // columns will be zeroed
            for (int j = 0; j < myArray.length; j++) {
                System.out.print(myArray[i][j] + ",");
            if(j == myArray.length-1)
                System.out.println();
            }
        }

    }

    public static void main(String[] args) {
        int[][] a = { { 1, 0, 1, 1, 0 }, { 0, 1, 1, 1, 0 }, { 1, 1, 1, 1, 1 },
                { 1, 0, 1, 1, 1 }, { 1, 1, 1, 1, 1 } };
        zeroOut(a);
    }
}

0

İşte benim test dahil Ruby uygulaması, Bu O (MN) yer alacaktı. Gerçek zamanlı bir güncelleme istiyorsak (sıfırları bulmanın ilk döngüsünü beklemek yerine sıfırları bulduğumuzda sonuçları göstermek gibi) sadece başka bir sınıf değişkeni oluşturabiliriz @outputve sıfır bulduğumuzda @outputve güncellediğimizde değil @input.

require "spec_helper"


class Matrix
    def initialize(input)
        @input  = input
        @zeros  = []
    end

    def solve
        @input.each_with_index do |row, i|          
            row.each_with_index do |element, j|                             
                @zeros << [i,j] if element == 0
            end
        end

        @zeros.each do |x,y|
            set_h_zero(x)
            set_v_zero(y)
        end

        @input
    end


    private 

    def set_h_zero(row)     
        @input[row].map!{0}     
    end

    def set_v_zero(col)
        @input.size.times do |r|
            @input[r][col] = 0
        end
    end
end


describe "Matrix" do
  it "Should set the row and column of Zero to Zeros" do
    input =  [[1, 3, 4, 9, 0], 
              [0, 3, 5, 0, 8], 
              [1, 9, 6, 1, 9], 
              [8, 3, 2, 0, 3]]

    expected = [[0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0],
                [0, 9, 6, 0, 0],
                [0, 0, 0, 0, 0]]

    matrix = Matrix.new(input)

    expect(matrix.solve).to eq(expected)
  end
end

0

Aşağıdaki kod, m, n boyutunda bir matris oluşturur. İlk önce matrisin boyutlarına karar verin. [M] [n] matrisini 0..10 arasındaki sayılarla rastgele doldurmak istedim. Daha sonra aynı boyutlarda başka bir matris oluşturun ve -1 ile doldurun (son matris). Sonra 0'a basıp basmayacağınızı görmek için ilk matrisi tekrarlayın. (X, y) konumuna vurduğunuzda, son matrise gidin ve x satırını 0s ve y sütununu 0s ile doldurun. Sonunda son matrisi okuyun, değer -1 ise (orijinal değer), başlangıç ​​matrisinin aynı konumundaki değeri finale kopyalayın.

public static void main(String[] args) {
    int m = 5;
    int n = 4;
    int[][] matrixInitial = initMatrix(m, n); // 5x4 matrix init randomly
    int[][] matrixFinal = matrixNull(matrixInitial, m, n); 
    for (int i = 0; i < m; i++) {
        System.out.println(Arrays.toString(matrixFinal[i]));
    }
}

public static int[][] matrixNull(int[][] matrixInitial, int m, int n) {
    int[][] matrixFinal = initFinal(m, n); // create a matrix with mxn and init it with all -1
    for (int i = 0; i < m; i++) { // iterate in initial matrix
        for (int j = 0; j < n; j++) {
            if(matrixInitial[i][j] == 0){ // if a value is 0 make rows and columns 0
                makeZeroX(matrixFinal, i, j, m, n); 
            }
        }
    }

    for (int i = 0; i < m; i++) { // if value is -1 (original) copy from initial
        for (int j = 0; j < n; j++) {
            if(matrixFinal[i][j] == -1) {
                matrixFinal[i][j] = matrixInitial[i][j];
            }
        }
    }
    return matrixFinal;
}

private static void makeZeroX(int[][] matrixFinal, int x, int y, int m, int n) {
        for (int j = 0; j < n; j++) { // make all row 0
            matrixFinal[x][j] = 0;
        }
        for(int i = 0; i < m; i++) { // make all column 0
            matrixFinal[i][y] = 0; 
        }
}

private static int[][] initMatrix(int m, int n) {

    int[][] matrix = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            Random rn = new Random();
            int random = rn.nextInt(10);
            matrix[i][j] = random;
        }
    }

    for (int i = 0; i < m; i++) {
        System.out.println(Arrays.toString(matrix[i]));
    }
    System.out.println("******");
    return matrix;
}

private static int[][] initFinal(int m, int n) {

    int[][] matrix = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            matrix[i][j] = -1;
        }
    }
    return matrix;
}

// another approach
/**
 * @param matrixInitial
 * @param m
 * @param n
 * @return
 */
private static int[][] matrixNullNew(int[][] matrixInitial, int m, int n) {
    List<Integer> zeroRowList = new ArrayList<>(); // Store rows with 0
    List<Integer> zeroColumnList = new ArrayList<>(); // Store columns with 0
    for (int i = 0; i < m; i++) { // read through the matrix when you hit 0 add the column to zeroColumnList and add
                                  // the row to zeroRowList
        for (int j = 0; j < n; j++) {
            if (matrixInitial[i][j] == 0) {
                if (!zeroRowList.contains(i)) {
                    zeroRowList.add(i);
                }
                if (!zeroColumnList.contains(j)) {
                    zeroColumnList.add(j);
                }
            }
        }
    }

    for (int a = 0; a < m; a++) {
        if (zeroRowList.contains(a)) { // if the row has 0
            for (int b = 0; b < n; b++) {
                matrixInitial[a][b] = 0; // replace all row with zero
            }
        }
    }

    for (int b = 0; b < n; b++) {
        if (zeroColumnList.contains(b)) { // if the column has 0
            for (int a = 0; a < m; a++) {
                matrixInitial[a][b] = 0; // replace all column with zero
            }
        }
    }
    return matrixInitial;
}

Gönderdiğiniz koda herhangi bir açıklama veya bağlam vermiyorsunuz.
Aaron

Umarım şimdi daha iyi. Uyarı için teşekkürler. Sizin için net değilse, daha fazla açıklamak istiyorum.
user3743369

0

işte benim çözümüm. Koddan da görebileceğiniz gibi, bir M * N matrisi verildiğinde, bu satırdaki bir sıfırı inceledikten sonra tüm satırı sıfıra ayarlar. Benim çözümümün zaman karmaşıklığı O (M * N). Konsolda sonucu görmek için statik bir kalabalık dizisi ve bir görüntü dizisi yöntemi olan tüm sınıfı paylaşıyorum.

public class EntireRowSetToZero {
    static int arr[][] = new int[3][4];
    static {

    arr[0][0] = 1;
    arr[0][1] = 9;
    arr[0][2] = 2;
    arr[0][3] = 2;

    arr[1][0] = 1;
    arr[1][1] = 5;
    arr[1][2] = 88;
    arr[1][3] = 7;

    arr[2][0] = 0;
    arr[2][1] = 8;
    arr[2][2] = 4;
    arr[2][3] = 4;
}

public static void main(String[] args) {
    displayArr(EntireRowSetToZero.arr, 3, 4);
    setRowToZero(EntireRowSetToZero.arr);
    System.out.println("--------------");
    displayArr(EntireRowSetToZero.arr, 3, 4);


}

static int[][] setRowToZero(int[][] arr) {
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < arr[i].length; j++) {
            if(arr[i][j]==0){
                arr[i]=new int[arr[i].length];
            }
        }

    }
    return arr;
}

static void displayArr(int[][] arr, int n, int k) {

    for (int i = 0; i < n; i++) {

        for (int j = 0; j < k; j++) {
            System.out.print(arr[i][j] + " ");
        }
        System.out.println("");
    }

}

}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.