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) ?
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) ?
Yanıtlar:
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 vezaten 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 .
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 ).
// 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 olarak-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.
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öntemiBu durumda boyutunda işlemleri ; bu yüzden model değişikliğine rağmen kaba kuvvetten daha iyi olan bit işlemlerini yapar ).
Yine de yaklaşımının varlığı hakkındaki soru hala ilginçtir.
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.
mat[i]
mat[j]
mat
hangisinin ö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 .
mat
- sanırım kullanmalıyız std::vector<boost::dynamic_bitset<int64_t>>
.
mat
: evet, aslında standart bitset'i aklımda tuttum, ancak boost::dynamic_bitset
bu 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.