洛谷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)|之和。

 

输入输出样例

输入样例#1: 复制
4 3
2
3
1
1
1 4 30
2 3 20
3 4 20
输出样例#1: 复制
9

说明

输出解释: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 }
View Code

从此你可以向别人炫耀说我用n遍spfa这种大暴力还能a题233

posted @ 2018-01-02 22:10  lonlyn  阅读(328)  评论(0编辑  收藏  举报