借鉴博客:https://www.cnblogs.com/zhangjiuding/p/9112273.html
986-A. Fair
/* 986-A-Fair,codeforce;
大致题意:
n个点,m个双向边; 一共K中食品,每个点只能提供1种;至少携带s种不同的食品,点u->v 需要花费d(u,v);d(u,v)是最短路u->v,的开销——开销等于该最短路的路径中的边数。每个点有一种食品,食品总的种类数不超过K个,求从每个点出发找至少种食品的最小开销。题目看着像是最短路,起个名字叫做类最短路题目!
大致思路:
直接进行裸的bfs,我的第一次的做法是枚举每个点作为单源点进行bfs的,这样时间复杂度最大为:(10^5)*(10^5)=顶点数*边数!尽管k只有100个,按理说找100个点不就够了-但可能出现极端情况,比如某几个点特别离散——很偏僻需要搜完整个图才可以找到,这样整个图的复杂度就上升很多了!
怎么解决呢?再次审题找到突破口,k=100,然后就需要从突破口开始这k种食品的地方进行bfs,每次bfs某一种型号的食品——将该种型号食品的产地作为bfs的起点——更省时!复杂度为k*(10^5)=k *顶点数,及从每种食品开始bfs搜索完整个图存进d[][]中!
*/
1 #define N 100008 2 int a[N]; 3 vector<int>G[N]; 4 int d[N][108];//更新每个小镇到第i种食物的最小距离 5 6 void init(int n){ 7 for(int i=0;i<=n;i++) 8 G[i].resize(0); 9 } 10 bool vis[N]; 11 12 bool used[N]; 13 void bfs(int k,int n){ 14 queue<int>Q; 15 for(int i=1;i<=k;i++){//暴力枚举第i种物品的源点,从每种物品的源点开始进行bfs!更省时! 16 memset(used,false,sizeof(used)); 17 for(int j=1;j<=n;j++){ 18 if(a[j]==i){ 19 d[j][i]=0; 20 Q.push(j); 21 used[j]=true; 22 } 23 } 24 while(Q.size()>0){//进行BFS! 25 int x=Q.front(); 26 Q.pop(); 27 for(int t=0;t<(int)G[x].size();t++){ 28 int v=G[x][t]; 29 if(!used[v]){ 30 d[v][i]=d[x][i]+1;//bfs记录节点 31 used[v]=true; 32 Q.push(v); 33 } 34 } 35 } 36 } 37 } 38 39 int main(){ 40 int n,m,k,s; 41 42 while(scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF){ 43 init(n); 44 for(int i=1;i<=n;i++) 45 scanf("%d",&a[i]); 46 int x,y; 47 for(int i=1;i<=m;i++){ 48 scanf("%d%d",&x,&y); 49 G[x].push_back(y); 50 G[y].push_back(x); 51 } 52 bfs(k,n); 53 54 for(int i=1;i<=n;i++){ 55 sort(d[i]+1,d[i]+1+k); 56 int ans=0; 57 for(int j=1;j<=s;j++){ 58 ans+=d[i][j]; 59 } 60 printf("%d ",ans); 61 } 62 cout<<endl; 63 } 64 return 0; 65 }