POJ 2607

题意: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 }

你可能感兴趣的:(poj)