下面是題面。
【問題描述】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...