伺服器儲存資訊問題 差分約束

2022-05-02 03:42:08 字數 3168 閱讀 9131

下面是題面。

【問題描述】

byteland 王國準備在各伺服器間建立大型網路並提供多種服務。

網路由 n 臺伺服器組成,用雙向的線連線。

兩台伺服器之間最多只能有一條線直接連線,同時,每台伺服器最多只能和 10 臺伺服器直接連線,但是任意兩台伺服器間必然存在一條路徑將它們連線在一起。

每條傳輸線都有乙個固定傳輸的速度。δ (v , w) 表示伺服器 v 和 w 之間的最短路徑長度,且對任意的 v 有δ (v , v)=0 。

有些伺服器比別的伺服器提供更多的服務,它們的重要程度要高一些。我們用 r(v) 表示伺服器 v 的重要程度 (rank) 。 rank 越高的伺服器越重要。

每台伺服器都會儲存它附近的伺服器的資訊。當然,不是所有伺服器的資訊都存,只有感興趣的伺服器資訊才會被儲存。

伺服器 v 對伺服器 w 感興趣是指,不存在伺服器 u 滿足,r(u)>r(w) 且δ (v , u)<= δ (v ,w)

舉個例子來說,所有具有最高 rank 的伺服器都會被別的伺服器感興趣。

如果 v 是一台具有最高 rank 的伺服器,由於δ (v , v) =0 ,所以 v 只對具有最高 rank 的伺服器感興趣。我們定義 b(v) 為 v 感興趣的伺服器的集合。

我們希望計算所有伺服器儲存的資訊量,即所有伺服器的| b(v) |之和。

byteland 王國並不希望儲存大量的資料,所以所有伺服器儲存的資料量 ( | b(v) |之和 )不會超過 30n

你的任務是寫乙個程式,讀入 byteland 王國的網路分布,計算所有伺服器儲存的資料量。

【輸入】

第一行兩個整數 n 和 m , (1 ≤ n ≤ 30 000 , 1 ≤ m ≤ 5n) 。 n 表示伺服器的數量, m 表示傳輸線的數量。

接下來 n 行,每行乙個整數,第 i 行的整數為 r(i)(1 ≤ r(i) ≤ 10) ,表示第 i 臺伺服器的rank 。

接下來 m 行,每行表示各條傳輸線的資訊,包含三個整數 a , b , t(1 ≤ t ≤ 1000 , l ≤ a , b ≤ n , a ≠ b) 。

a 和 b 是傳輸線所連線的兩台伺服器的編號, t 是傳輸線的長度。

【輸出】

乙個整數,表示所有伺服器儲存的資料總量,即| b(v) |之和。

【樣例】

servers.in

4 3231

11 4 30

2 3 20

3 4 20

servers . out

9注: b(1)= , b(2)= , b(3)= , b(4)= 。

我們發現暴力很好想也很好寫,做n遍spfa,再按rank把點掃一遍就好了,複雜度大概是平方級的。

那麼正解應該是在這上面的優化。

注意到最終的答案不會超過30n,但是點對有n^2個?所以說這應該是乙個剪枝點。

同時發現rank<=10?

有乙個非常重要的資料,點x到rank為i的點集的最短路徑。有了這個可以方便很多計算,這也是rank很小的原因之一。

於是我們把它記為 far[i][x];

然後我們可以擴充套件一下它的含義:"x到rank為i的點集的最短路徑"可以換成"x到rank大於等於i的點集的最短路徑"。

這樣我們一次比較u和v,就只要看一下:far(u,v)

那麼接下來來剪上面那個枝。

現在我們以w為起點,找到了乙個點v,而v不關心w;

不滿足關係的條件為: far(w,v) >= far[rank[w]+1][v];

若我們把v扔進佇列進行接下來的spfa鬆弛,假設v鬆弛到u;

由spfa性質得此時 far(u,w)=far(w,v)+far(v,u);

而 far(w,v) >= far[rank[w]+1][v];

所以 far(w,u)

=far(u,v)+far(v,w)

>=far(u,v)+far[rank[w]+1][v]

>=far[rank[w]+1][u];

所以此時u也是不對w感興趣的點。

這告訴我們:spfa到乙個不滿足條件的點,你大可不必將它放進佇列裡。

因為題目告訴我們答案不超過30n,所以spfa的複雜度均攤下來很小。

於是你切完這題後就可以跟別人說:"啊?我做了n遍spfa就過了啊!"

聽上去似乎有那麼點道理... ...

#include    #include    #include    #include    #include    #include    #include    #define ll long long int

#define ls (x << 1)

#define rs (x << 1 | 1)

#define rank bobo

using namespace std;

const int n = 30010;

const int m = n*10;

struct dataedge[n];

struct nodee[m];

int n,m,head[12],tot,head[n],tot,rank[n];

int ans,far[12][n],far[n],in[n],vis[n];

int gi()

while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();

return x*res;

}inline void link(int u,int v)

; head[u]=tot;

}inline void link(int u,int v,int c)

; head[u]=tot;

}inline void spfa1(int p)

while(!q.empty())

inline void spfa(int p)}}}

int main()

for(int i=1;i<=m;++i)

for(int i=1;i<=10;++i)spfa1(i);

for(int i=9;i;--i)ts(i);

for(int i=1;i<=n;++i)spfa(i);

printf("%d\n",ans);

return 0;

}

差分約束問題

給定 n 個區間 ai,bi 和 n 個整數 ci 你需要構造乙個整數集合 z,使得 i 1,n z 中滿足ai x bi的整數 x 不少於 ci 個。求這樣的整數集合 z 最少包含多少個數。輸入格式 第一行包含整數 n。接下來n行,每行包含三個整數ai,bi,ci。輸出格式 輸出乙個整數表示結果。...

差分約束 解決區間選點問題

給定乙個數軸上的 n 個區間,要求在數軸上選取最少的點使得第 i 個區間 ai,bi 裡至少有 ci 個點。輸入第一行乙個整數 n 表示區間的個數,接下來的 n 行,每一行兩個用空格隔開的整數 a,b 表示區間的左右端點。1 n 50000,0 ai bi 50000 並且 1 ci bi ai 1...

區間選點 差分約束系統問題

給定乙個數軸上的 n 個區間,要求在數軸上選取最少的點使得第 i 個區間 ai,bi 裡至少有 ci 個點。輸入第一行乙個整數 n 表示區間的個數,接下來的 n 行,每一行兩個用空格隔開的整數 a,b 表示區間的左右端點。1 n 50000,0 ai bi 50000 並且 1 ci bi ai 1...