题意:n个点的无向带权图,上面有f个消防站,现在要添加一个消防站,求一个最好且最小的标号的方法,使得原图中每个点到它最近的消防站的距离中的最大值要最小。

题解:1、以f个消防站所在位置为起点,做一次spfa求出它们到其他所有点的最小距离。

     2、枚举每个点,从该点出发求一次spfa求出它到所有点的距离。在该点放消防站的代价就是max(所有的i=>min(d[i],dist[i]))。

   3、PS:消防站可能一开始就遍布整个图,即,每个点都有消防站,此时,理论上是不用放的,但是ZF钱太多,还是要建一座,就是第1座,所以枚举是要赋初值= =!。

View Code
  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<queue>
  5 using namespace std;
  6 const int N=5050,inf=10000;
  7 int head[N],nc,n;
  8 struct Edge
  9 {
 10     int to,next,cost;
 11 }edge[100000];
 12 void add(int a,int b,int c)
 13 {
 14     edge[nc].to=b;edge[nc].next=head[a];edge[nc].cost=c;head[a]=nc++;
 15     edge[nc].to=a;edge[nc].next=head[b];edge[nc].cost=c;head[b]=nc++;
 16 }
 17 int dist[N];
 18 int stk[N],f,r;
 19 bool vis[N];
 20 void fire_spfa(int fire[],int num)
 21 {
 22     memset(vis,false,sizeof(vis));
 23     f=r=0;
 24     for(int i=0;i<num;i++)
 25     {
 26         int t=fire[i];
 27         if(!vis[t])
 28         {
 29             vis[t]=true;
 30             dist[stk[r++]=t]=0;
 31         }
 32     }
 33     while(f!=r)
 34     {
 35         int now=stk[f++];
 36         if(f==N)f=0;
 37         vis[now]=false;
 38         for(int i=head[now];i!=-1;i=edge[i].next)
 39         {
 40             int to=edge[i].to,cc=edge[i].cost;
 41             if(dist[to]>dist[now]+cc)
 42             {
 43                 dist[to]=dist[now]+cc;
 44                 if(!vis[to])
 45                 {
 46                     stk[r++]=to;
 47                     if(r==N)r=0;
 48                     vis[to]=true;
 49                 }
 50             }
 51         }
 52     }
 53 }
 54 int new_spfa(int src)
 55 {
 56     memset(vis,false,sizeof(vis));
 57     f=0,r=1;
 58     vis[src]=true;
 59     int d[N];
 60     for(int i=1;i<=n;i++)
 61         d[i]=inf;
 62     d[src]=0;
 63     stk[0]=src;
 64     while(f!=r)
 65     {
 66         int now=stk[f++];
 67         if(f==N)f=0;
 68         vis[now]=false;
 69         for(int i=head[now];i!=-1;i=edge[i].next)
 70         {
 71             int to=edge[i].to;
 72             int cc=edge[i].cost;
 73             if(d[to]>d[now]+cc)
 74             {
 75                 d[to]=d[now]+cc;
 76                 if(!vis[to])
 77                 {
 78                     stk[r++]=to;
 79                     vis[to]=true;
 80                     if(r==N)r=0;
 81                 }
 82             }
 83         }
 84     }
 85     int ans=0;
 86     for(int i=1;i<=n;i++)
 87     {
 88         ans=max(ans,min(d[i],dist[i]));
 89     }
 90     return ans;
 91 }
 92 int main()
 93 {
 94     int ff,fire[N],a,b,c;
 95     memset(head,-1,sizeof(head));
 96     nc=0;
 97     scanf("%d%d",&ff,&n);
 98     for(int i=0;i<ff;i++)
 99         scanf("%d",fire+i);
100     while(scanf("%d%d%d",&a,&b,&c)!=EOF)
101         add(a,b,c);
102     for(int i=1;i<=n;i++)
103         dist[i]=inf;
104     fire_spfa(fire,ff);
105     int id=1,ans=inf;
106     for(int i=1;i<=n;i++)
107     {
108         if(dist[i]!=0)
109         {
110             int tp=new_spfa(i);
111             if(ans>tp)
112             {
113                 ans=tp;
114                 id=i;
115             }
116         }
117     }
118     printf("%d\n",id);
119     return 0;
120 }