度小滿2018.9.26筆試 鏈式邊權
題目描述
n個點,有n-1條邊,每條邊的權值被這樣計算: 在邊左面的點稱為x,在邊右面的點稱為y。x≠y。有多少這樣的點對,那麼這條邊的權值就為多少。 提示: 第一條邊能形成一個點對(1,2) 第二條邊能形成一個點對(2,1) 所以,輸出為1 1
動態規劃
#include <pch.h>//vs2017建控制檯程式自帶的預編譯標頭檔案
#include <stdio.h>
#include <vector>
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n), w(n);//w存邊的權值
for (int i = 0; i < n; i++) {
scanf_s("%d", &a[i]);
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
if (a[j] != a[i]) {
w[i]++;
w[j]--;
}
}
if (i != 0) {
w[i] = w[i] + w[i - 1];
}
printf("%d " , w[i]);
}
return 0;
}
重點解釋一下,內層迴圈裡面的加加和減減吧,還有w[i] = w[i] + w[i - 1];
,這句一看就是很像是動態軌跡裡面的遞推式。
以一個實際例子講解吧:
輸入:
4
1 2 3 4
輸出:
3 4 3
初始時: 執行完第一次外層迴圈後: 就得到了第一條邊的權值,權值為3的含義是有這三個點對。剩下三個點的權值都為-1,假如1稱為已經記錄的點,那麼這個-1就代表當前點與已記錄點之間能形成多少點對,比如2這個點與已記錄點1之間能形成一個點對(1,2),所以2點在當前的權值為-1。(注意這裡以及之後的“權值”不是指原題中指的權值)
執行完第二次外層迴圈後:
第三次外層迴圈也是一個道理。
總結一下: 1.第i次迴圈結束後,第i條邊的權值會被記錄。也稱0 - i的點們已經被記錄,因為0 - i的點們和i+1 - n-1的點們之間能形成的點對數量已經被w[i]所記錄,也就是題意的意思。
2.第i次迴圈結束後,從i+1 - n-1的點的權值也會被更新:注意i+1 - n-1的點們的權值必為負值,他的絕對值是指,當前點與已經記錄的點之間形成的點對數量。
3.除開第一次外層迴圈,每次外層迴圈i中,對w{i}的更新都是兩部分:第一是當前點i與邊右面的點之間形成的點對數,這個是用內層迴圈做的;第二是0 - i-1的點們與邊右面的點之間形成的點對數,這個資訊已經被w[i-1]儲存,但資訊不是都需要的,需要除開0 - i-1的點們與點i之間形成的點對數,而這個需要除開的數量剛好就是當前w[i]存的負值的絕對值。
動態規劃
這是第二種用法,python3程式碼。思路與上一種完全一樣,但具體細節實現有所不同。
首先重點理解下我這句話,要得到一個數x和一個數的陣列yArray之間可以形成多少個點對,只需要得到yArray的長度減去yArray中x的數量。
使用了collections.Counter()
,是計數器的功能,可以得到一個鍵值key出現的次數。
import collections
n = eval(input())
a = list(map(int,input().split()))
lw = collections.Counter()
l_count = 0
rw = collections.Counter(a)
r_count = n
res = [0] * (n-1)
for i in range(n-1):
lw[a[i]] += 1
l_count += 1
rw[a[i]] -= 1
r_count -= 1
res[i] = res[i-1] + (r_count - rw[a[i]]) - (l_count - lw[a[i]])
#第0次迴圈不需要單獨加判斷,因為res[-1]=res[0]=0
print( ' '.join(map(str,res)))
和上一種程式碼一樣,在每次迴圈i中,(r_count - rw[a[i]])
代表了當前點i與邊右面的點之間形成的點對數。res[i-1] - (l_count - lw[a[i]])
代表0 - i-1的點們與邊右面的點之間形成的點對數,這個資訊已經被res[i-1]
儲存,但需要除開一部分資訊即0 - i-1的點們與點i之間形成的點對數,需要除開的資訊剛好就是(l_count - lw[a[i]])
,注意lw[a[i]])
至少為1。
再解釋一下,這個需要除開的資訊,就是,邊左面的點的數量減去邊左面的點中a[i]
出現的次數,即為0 - i-1的點們與點i之間形成的點對數。