Aşağıdaki sorun için bir subkübik algoritma var mı?


11

Simetrik bir gerçek matrisi verildiğinde, baştan 1 \ leq i <j <k \ leq n zaman karmaşıklığı ile daha iyi O (n ^ 3) ?n×nA=(aij)

i,j,kmax(aij,aik,ajk)
1i<j<knO(n3)

3
Bunun en azından belirli bir grafikteki üçgen sayısını saymak kadar zor olduğunu unutmayın . Giriş matrisiniz "0" bir kenarı ve "1" eksik bir kenarı gösterecek şekilde bir grafik kodlarsa , \ max (a_ {ij}, a_ {ik}, a_ {jk}) = 0max(aij,aik,ajk)=0 ise ve yalnızca varsa i , j ve k düğümlerinden oluşan bir üçgendir k, aksi takdirde 1 .
Jukka Suomela

1
Üçgen sayımı için bilinen tek önemli subcubic algoritma hızlı matris çarpma dayanmaktadır düşünüyorum? Bu tekniklerin bu problemde burada uygulanması zor olabilir. Ayrıca, pratik bir şey arıyorsanız, hızlı matris çarpımına dayanan herhangi bir şey yardımcı olmayacaktır.
Jukka Suomela

Yanıtlar:


3

zamanında çalışan oldukça pratik bir yaklaşım vardır , burada işlemci kelimesindeki bit sayısıdır. Ana fikir, matrisin elemanları üzerinde artan sırayla (keyfi olarak kopukluklar) teker teker yinelemeniz ve "bunları açmanız" dır. Bazı üçlü öğelerinin en büyük öğesinin açıldığı anı düşünün . Basit olması için, söz konusu öğenin olduğunu varsayalım . Son eleman açıldığında, üçlü değerini şimdi cevaba eklemek doğaldır. Bu yüzden olası sayısını saymak zorundayız ki veO(n3/w)waij,aik,ajkaijkaikajkzaten açıktır (bu üçlü sayısıdır, burada en büyük elementtir, bu yüzden şimdi tamamen açılmışlardır). Burada bit optimizasyonu kullanarak saf uygulamasını hızlandırabiliriz .aijO(n)

Ayrıntılar için, , (çok optimize edilmemiştir; ancak yine de için saf toplamı en azından makinemde büyük marjla yener ).n5000|aij|109n=5000

// code is not very elegant, 
// but should be understandable
// here the matrix a has dimensions n x n
// a has to be symmetric!
int64_t solve (int n, const vector<vector<int32_t>> &a)
{
        std::vector<boost::dynamic_bitset<int64_t>> mat
        (n, boost::dynamic_bitset<int64_t>(n));

        vector<pair<int, int>> order;
        for (int j = 1; j < n; j++)
        for (int i = 0; i < j; i++)
            order.emplace_back(i, j);
        sort(order.begin(), order.end(),
            [&] (const pair<int, int> &l, const pair<int, int> &r) 
            {return a[l.first][l.second] < a[r.first][r.second];});

        int64_t ans = 0;
        for (const auto &position : order)
        {
            int i, j;
            tie (i, j) = position;
            mat[i][j] = mat[j][i] = 1;
            // here it is important that conditions 
            // mat[i][i] = 0 and mat[j][j] = 0 always hold
            ans += (mat[i] & mat[j]).count() * int64_t(a[i][j]);
        }

        return ans;
}

Bit optimizasyonlarını hile kullanmayı düşünüyorsanız, burada aynı sonuca dört rus yöntemi kullanabilirsiniz, daha az pratik olması gereken bir algoritması sağlar (çünkü çoğu modern donanımda oldukça büyüktür) ama teorik olarak daha iyi. Gerçekten de, izin en tercih ve bir dizi olarak matrisin her satır tutmak arasındaki tam sayıları ile , burada -inci sayısı olarak arasında değişen sıranın bit dizisi karşılık dahil etmek özel olarakO(n3/logn)wblog2nnb02b1iibmin(n,(i+1)b)0-indexation. zamanında her iki bloğun skaler ürünlerini önceden hesaplayabiliriz . Matristeki bir konumu güncellemek hızlıdır çünkü yalnızca bir tamsayıyı değiştiriyoruz. ve sıralarının skaler çarpımını bulmak için sadece bu sıralara karşılık gelen diziler üzerinde tekrarlayın, tablodaki karşılık gelen blokların skaler ürünlerine bakın ve elde edilen ürünleri toplayın.O(22bb)ij

Yukarıdaki paragraf tamsayılar ile bu işlemleri varsayar almak zaman. Öyle oldukça yaygın varsayım biz bu varsayımı kullanmazsanız genellikle aslında, örneğin (algoritmaların karşılaştırmalı hızını değiştirmez, çünkü kaba kuvvet yöntemi aslında çalışır burada zaman ( bit işlemlerindeki süreyi ölçeriz) bazı sabit için en az kadar mutlak değerlerle tamsayı değerleri alırsa (ve aksi takdirde yine de matris çarpımları); ancak yukarıda önerilen dört rusça yönteminO(1)O(n3logn)aijnεε>0O(nε)O(n3/logn)Bu durumda boyutunda işlemleri ; bu yüzden model değişikliğine rağmen kaba kuvvetten daha iyi olan bit işlemlerini yapar ).O(logn)O(n3)

Yine de yaklaşımının varlığı hakkındaki soru hala ilginçtir.O(n3ε)

Bu cevapta sunulan teknikler (bit optimizasyonları ve dört rus yöntemi) hiçbir şekilde orijinal değildir ve burada serginin bütünlüğü için sunulmaktadır. Ancak, bunları uygulamak için bir yol bulmak önemsiz değildi.


İlk olarak, önerileriniz gerçekten pratik açıdan yararlı görünüyor, sadece kullanım durumumda deneyebilirim. Teşekkürler! İkincisi, herhangi bir sabit genişlikli sayısal tip için algoritma hesaplama karmaşıklığı hala . yaklaşımından bahsedebilir misiniz ? nin skaler ürününü nasıl ve daha hızlı bulabileceğimi anlamıyorum (tüm elemanlarına erişirsek gerekli olur). O(n3)O(n3/logn)mat[i]mat[j]O(n)
user89217

Ayrıca, kodunuz mathangisinin önemli göründüğünü tanımlamaz . Nasıl tanımlanabileceğini anlıyorum, ancak (mat[i] & mat[j]).count()herhangi bir STL konteyneri ile istediğiniz gibi çalışıp çalışmayacağını merak ediyorum .
user89217 15:18

1
Hakkında mat- sanırım kullanmalıyız std::vector<boost::dynamic_bitset<int64_t>>.
user89217

İlgili olarak mat: evet, aslında standart bitset'i aklımda tuttum, ancak boost::dynamic_bitsetbu durumda daha da iyi, çünkü boyutunun derleme zamanı sabiti olması gerekmiyor. Bu ayrıntıyı eklemek ve dört Rus yaklaşımını netleştirmek için cevabı düzenleyecek.
Kaban-5

1
Harika, bu bana sağlam geliyor. Küçük bir nokta: transdikotom model 'de makine kelimeleri üzerinde işlem yapabileceğimizi varsaydığından , herhangi bir skaler ürünü önceden hesaplamaya gerek yoktur. Aslında, bir model olduğunu varsayar , böylece olarak da iyi olarak en az bir . Söylediğiniz gibi, skaler ürünleri önceden hesaplamak pratik bir anlam ifade etmez (bir dizi arama ikili op'tan daha yavaş olacaktır). O(1)wlog2nO(n3/w)O(n3/logn)
user89217
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.