洛谷P1261 服务器储存信息问题
题目:https://www.luogu.org/problemnew/show/1261
题目描述
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≤30000,1≤m≤5n)。n表示服务器的数量,m表示传输线的数量。
接下来n行,每行一个整数,第i行的整数为r(i)(1≤r(i)≤10),表示第i台服务器的rank。
接下来m行,每行表示各条传输线的信息,包含三个整数a,b,t(1≤t≤1000,1≤a,b≤n,a≠b)。a和b是传榆线所连接的两台服务器的编号,t是传输线的长度。
输出格式:
一个整数,表示所有服务器存储的数据总量,即|B(V)|之和。
输入输出样例
说明
输出解释:B(1)={1,2},B(2)={2},B(3)={2,3},B(4)={1,2,3,4}。
解析
暴力做法就是n遍spfa,然后按照rank怼一遍就完事了。
不过能得多少分我就不知道了。。。。。。
有兴趣的同学可以试一下orz,我就不作了。
正解当然要对这个求解方案进行优化了啊。
怎么优化呢?orz
注意到rank似乎非常小,那就对rank搞点事情。
一般都能想到记录点x到rank为i的点集的最短路径,但我们为了以后方便可以扩展一下为 x到rank大于等于i的点集的最短路径 ,设为F[i][x]。
这样每次比较u,v就只要看一看dis(u,v)<F[rank[v]+1][u]。
我们对他优化一下orz。
以起点s开始找到一个点v,设v不关心s,则dis(s,v)>=F[rank[s]+1][v];
若我们尝试把v扔进队列,假设松弛到u,
则dis(s,u)=dis(s,v)+dis(v,u);
But dis(s,v)>=F[rank[s]+1][v];
So dis(s,u)=dis(s,v)+dis(v,u)>=F[rank[s]+1][v]+dis(u,v)>=F[rank[s]+1][u];
所以此时u也是不对w感兴趣的点,我们还给他扔进去干嘛。。
答案不超过30n,复杂度不算高。
这道题告诉我们:spfa到一个不满足条件的点就不要把它扔到队列里面去了嘛。
(真理:暴力出奇迹)
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 struct node{ 10 int to; 11 int v; 12 }; 13 vector<node> edge; 14 vector<int> G[30010]; 15 vector<int> o_edge[20]; 16 int n,m; 17 int r[30010]; 18 int u,v,t; 19 int far[20][30010]; 20 int dis[30010]; 21 bool vis[30010]; 22 bool ok[30010]; 23 int ans; 24 25 void add_edge(int from,int to,int v){ 26 edge.push_back((node){to,v}); 27 edge.push_back((node){from,v}); 28 int m=edge.size(); 29 G[from].push_back(m-2); 30 G[to].push_back(m-1); 31 } 32 33 void o_spfa(int x){ 34 memset(vis,false,sizeof(vis)); 35 memset(far[x],0x3f,sizeof(far[x])); 36 queue<int> q; 37 for (int i=0;i<o_edge[x].size();++i){ 38 far[x][o_edge[x][i]]=0; 39 q.push(o_edge[x][i]); 40 } 41 while (!q.empty()){ 42 int now=q.front(); 43 q.pop(); 44 vis[now]=false; 45 for (int i=0;i<G[now].size();++i){ 46 node nxt=edge[G[now][i]]; 47 if (far[x][now]+nxt.v<far[x][nxt.to]){ 48 far[x][nxt.to]=far[x][now]+nxt.v; 49 if (!vis[nxt.to]){ 50 vis[nxt.to]=true; 51 q.push(nxt.to); 52 } 53 } 54 } 55 } 56 } 57 58 void wk(int x){ 59 for (int i=1;i<=n;++i){ 60 if (far[x][i]>far[x+1][i]) 61 far[x][i]=far[x+1][i]; 62 } 63 } 64 65 void spfa(int x){ 66 memset(vis,false,sizeof(vis)); 67 memset(dis,0x3f,sizeof(dis)); 68 memset(ok,false,sizeof(ok)); 69 dis[x]=0; 70 vis[x]=1; 71 queue<int> q; q.push(x); 72 while (!q.empty()){ 73 int now=q.front(); 74 q.pop(); 75 vis[now]=false; 76 if (!ok[now]){ 77 ans++; 78 ok[now]=true; 79 } 80 for (int i=0;i<G[now].size();++i){ 81 node nxt=edge[G[now][i]]; 82 if (dis[nxt.to]>dis[now]+nxt.v){ 83 dis[nxt.to]=dis[now]+nxt.v; 84 if (!vis[nxt.to]&&dis[nxt.to]<far[r[x]+1][nxt.to]){ 85 q.push(nxt.to); 86 vis[nxt.to]=true; 87 } 88 } 89 } 90 } 91 } 92 93 int main(){ 94 scanf("%d%d",&n,&m); 95 for (int i=1;i<=n;++i){ 96 scanf("%d",&r[i]); 97 o_edge[r[i]].push_back(i); 98 } 99 for (int i=1;i<=m;++i){ 100 scanf("%d%d%d",&u,&v,&t); 101 add_edge(u,v,t); 102 } 103 for (int i=1;i<=10;++i) o_spfa(i); 104 for (int i=9;i>=1;--i) wk(i); 105 for (int i=1;i<=n;++i) spfa(i); 106 cout<<ans; 107 return 0; 108 }
从此你可以向别人炫耀说我用n遍spfa这种大暴力还能a题233