【待重置】最小生成树各种题型

最小生成树(贪心算法)

tip:对于证明是否应该用贪心,只需要简单的证明一下,为什么取这种比取其他的优就行了。

讲解及证明:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html


Description



The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago. But the jungle overtakes roads relentlessly, so the large road network is too expensive to maintain. The Council of Elders must choose to stop maintaining some roads. The map above on the left shows all the roads in use now and the cost in aacms per month to maintain them. Of course there needs to be some way to get between all the villages on maintained roads, even if the route is not as short as before. The Chief Elder would like to tell the Council of Elders what would be the smallest amount they could spend in aacms per month to maintain roads that would connect all the villages. The villages are labeled A through I in the maps above. The map on the right shows the roads that could be maintained most cheaply, for 216 aacms per month. Your task is to write a program that will solve such problems. 

The input consists of one to 100 data sets, followed by a final line containing only 0. Each data set starts with a line containing only a number n, which is the number of villages, 1 < n < 27, and the villages are labeled with the first n letters of the alphabet, capitalized. Each data set is completed with n-1 lines that start with village labels in alphabetical order. There is no line for the last village. Each line for a village starts with the village label followed by a number, k, of roads from this village to villages with labels later in the alphabet. If k is greater than 0, the line continues with data for each of the k roads. The data for each road is the village label for the other end of the road followed by the monthly maintenance cost in aacms for the road. Maintenance costs will be positive integers less than 100. All data fields in the row are separated by single blanks. The road network will always allow travel between all the villages. The network will never have more than 75 roads. No village will have more than 15 roads going to other villages (before or after in the alphabet). In the sample input below, the first data set goes with the map above. 

The output is one integer per line for each data set: the minimum cost in aacms per month to maintain a road system that connect all the villages. Caution: A brute force solution that examines every possible set of roads will not finish within the one minute time limit. 
 

Sample Input

    
    
9 A 2 B 12 I 25 B 3 C 10 H 40 I 8 C 2 D 18 G 55 D 1 E 44 E 2 F 60 G 38 F 0 G 1 H 35 H 1 I 35 3 A 2 B 10 C 40 B 1 C 20 0
 

Sample Output

    
    
216 30



做法一(对点操作):党组织之树

每次贪心选离已选点系统(党组织)最近的一个点加入进来


代码1:Prim算法(用最短路Dij优化)

#include <iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;

#define inf 0x3f3f3f
int edge[36][36];
int N;
int dis[36];
bool vis[36];
void init()
{
     int i,j;
     for(i=1;i<=N;i++)
     {
          for(j=1;j<=N;j++)
          {
               edge[i][j]=inf;
          }
     }
}
/*前情提要:现在有一堆一起光屁股长大的人,每个人之间的关系有近有远,
(因为他们小时候为了抢玩具有的成了好兄弟,有的闹了矛盾,甚至老死不相往来)。
因为他们老是玩玩具,所以思想觉悟不高,一不小心走上了错误的道路。现在他们纠想要正自我,
走上正确的道路,于是积极入党想要学习。我们当然希望进党的同志离党组织的关系越近越好,
因为离党的关系越近,对党越忠心。所以在考虑谁入党的时候,都优先选离咱党组织关系近的那个*/
void prim()
{
     int i,j,mink,mm;
     int ans=0;
     for(i=1;i<=N;i++)
     {
          dis[i]=inf;
          /*dis[j]是到j点到党组织的关系,我们当然希望离党组织的关系越近越好。
          刚开始大家都没入党,所以离党组织的关系无限远*/
          vis[i]=false;//道路正确==是党员  道路错误==不是党员
          //现在每个人都还是懵逼的,没有入党,所以所走的道路是错误的
    }
     dis[1]=0;//党主席离党的关系当然是0
     for(i=1;i<=N;i++)//每个人都要全部入党,现在让第i个人入党
     {
          for(j=1,mm=inf;j<=N;j++)//我们现在选一个人推优入党,当然肯定选离咱党组织关系最近的那一个入党
          {
               if(dis[j]<=mm&&!vis[j])//每个人都在说:“看!我离党的关系最近,选我选我!”
               {//当然,已经入党的就不能来瞎掺和了
                    mm=dis[j];
                    mink = j;
               }
          }
          vis[mink]=true;//选出离党关系关系最近的那个人之后,他就从false变成了true,从此走上了正确的道路
          ans+=dis[mink];
          for(j=1;j<=N;j++)//进来一个,大家就都围上来想要拉近和党组织的关系,因为大家很踊跃
          {
               if(!vis[j] && edge[mink][j]<dis[j])//都已经是党员了就别来瞎掺和!
               {/*如果大家与这个新钦定者在当年光屁股长大的时候的关系(即edge[mink][j])
                   比自己目前离党组织的距离(即dis)近,现在这个小伙伴入党了,
                   那么他可以通过抱这个小伙伴的大腿,让自己离党组织的关系更近一步,
                    开心地等着之后继续拉近和党的关系或者被钦定*/
                    dis[j] = edge[mink][j];
               }
          }
     }
     printf("%d\n",ans);
}
int main()
{
     int n;
     char st[5],ed[5];
     int d;
     while(scanf("%d",&N) && N!=0)
     {
          init();
          for(int i=1;i<N;i++)
          {
               scanf("%s%d",st,&n);
               for(int j=1;j<=n;j++)
               {
                    scanf("%s%d",ed,&d);
                    edge[st[0]-'A'+1][ed[0]-'A'+1]=d;
                    edge[ed[0]-'A'+1][st[0]-'A'+1]=d;
               }
          }
          prim();
     }
     return 0;
}//FROM WCF



代码2:暴力,无优化

#include <iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;

#define inf 0x3f3f3f
int edge[36][36];
int N;
bool vis[36];
void init()
{
  int i,j;
  for(i=1; i<=N; i++)
    {
      vis[i]=false;
      for(j=1; j<=N; j++)
        {
          edge[i][j]=inf;
        }
    }
}
void prim()
{
  int i,j,k;
  int ans=0;
  vis[1] = true;
  for(i=1; i<N; i++)
    {
      int mink = 1;
      int mm= inf;
      for(j=1; j<=N; j++)//求非党员与党组织之间的最近关系,j是非党员,k是党员
        {
          if(vis[j]==true) continue;//已经是党员了就别来瞎掺和了
          int min = inf;
          for(k=1; k<=N; k++)
            {
              if(vis[k]==false) continue;//对没一个党员遍历
              min = edge[j][k]<min?edge[j][k]:min;
            }
          if(min<mm)
            {
              mm = min;
              mink = j;
            }
        }
      vis[mink]=true;
      ans+= mm;
    }
  printf("%d\n",ans);
}
int main()
{
  int n;
  char st[5],ed[5];
  int d;
  while(scanf("%d",&N) && N!=0)
    {
      init();
      for(int i=1; i<N; i++)
        {
          scanf("%s%d",st,&n);
          for(int j=1; j<=n; j++)
            {
              scanf("%s%d",ed,&d);
              edge[st[0]-'A'+1][ed[0]-'A'+1]=d;
              edge[ed[0]-'A'+1][st[0]-'A'+1]=d;
            }
        }
      prim();
    }
  return 0;
}//FROM YSF



做法二(对边操作):


Kruskal算法:对路径长度进行排序,贪心从小到大选择路径加入,如果成环则不能加入。注:非完全路径也适用于此方法


代码:

#include <iostream>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;

#define inf 0x3f3f3f

int N;
int pre[36];
int esum;

struct Edge
{
  int st,ed,len;
}edge[1010];

bool cmp(Edge a,Edge b)
{
  return a.len<b.len;
}

int find(int a)
{
  int a1=a;
  while(pre[a1]!=a1)
    a1=pre[a1];

  int a2=a;
  while(pre[a2]!=a2)
    {
      int tem=pre[a2];
      pre[a2]=a1;
      a2=tem;
    }
  return a1;
}

void kruskal()
{
  int i,x,y,ans=0;
  for(i=1; i<=N; i++)
    {
      pre[i]=i;
    }
  for(i=1; i<=esum; i++)
    {//不能成环才可以,并查集判断
      x=find(edge[i].st);
      y=find(edge[i].ed);
      if(x!=y)
        {
          ans = ans+edge[i].len;
          pre[x]=y;
        }
    }
  printf("%d\n",ans);
}
int main()
{
  int n;
  char St[5],Ed[5];
  int d;
  while(scanf("%d",&N) && N!=0)
    {
      esum=0;
      memset(edge,0,sizeof(edge));
      for(int i=1; i<N; i++)
        {
          scanf("%s%d",St,&n);
          for(int j=1; j<=n; j++)
            {
              scanf("%s%d",Ed,&d);
              esum++;
              edge[esum].st = St[0] -'A'+ 1;
              edge[esum].ed = Ed[0] -'A'+ 1;
              edge[esum].len = d;
            }
        }
      sort(edge+1,edge+esum+1,cmp);
      kruskal();
    }
  return 0;
}//FROM WCF

这里判断成环我想出这样的方法:如果加入一条边,就把这条边的两个端点book标记。之后判断是否成环的时候,如果两个端点都被标记了,那么就说明成环。这样就还能省下并查集的复杂度,由m*log2m变成m。

然而此法是错误的。

因为下面这种情况就不行了。




举一反三


应用1:

Description

There are N villages, which are numbered from 1 to N, and you should build some roads such that every two villages can connect to each other. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected. 

We know that there are already some roads between some villages and your job is the build some roads such that all the villages are connect and the length of all the roads built is minimum.

Input

The first line is an integer N (3 <= N <= 100), which is the number of villages. Then come N lines, the i-th of which contains N integers, and the j-th of these N integers is the distance (the distance should be an integer within [1, 1000]) between village i and village j. 

Then there is an integer Q (0 <= Q <= N * (N + 1) / 2). Then come Q lines, each line contains two integers a and b (1 <= a < b <= N), which means the road between village a and village b has been built.

Output

You should output a line contains an integer, which is the length of all the roads to be built such that all the villages are connected, and this value is minimum.

Sample Input

3
0 990 692
990 0 179
692 179 0
1
1 2

Sample Output

179


思路:因为有的村庄之间的路已经修好了,所以我刚开始拿到题的时候心想:人家都帮我修好路了,可万一那条路是很长的怎么办呢?我还选它吗?

你四不四傻啊!人家都帮你修好了,那么就说明需要你修的长度为0啊,真是2b。于是就秒了。


代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

#define inf 0x3f3f3f
int edge[105][105];
int N;
int dis[105];
bool vis[105];
void init()
{
  int i,j;
  for(i=1; i<=N; i++)
    {
      for(j=1; j<=N; j++)
        {
          edge[i][j]=inf;
        }
    }
}
void prim()
{
  int i,j,mink,mm;
  int ans=0;
  for(i=1; i<=N; i++)
    {
      dis[i]=inf;
      vis[i]=false;
    }
  dis[1]=0;
  for(i=1; i<=N; i++)
    {
      for(j=1,mm=inf; j<=N; j++)
        {
          if(dis[j]<=mm&&!vis[j])
            {
              mm=dis[j];
              mink = j;
            }
        }
      vis[mink]=true;
      ans+=dis[mink];
      for(j=1; j<=N; j++)
        {
          if(!vis[j] && edge[mink][j]<dis[j])
            {
              dis[j] = edge[mink][j];
            }
        }
    }
  printf("%d\n",ans);
}
int main()
{
    int i,j,a,b,q;
  while(~scanf("%d",&N))
    {
      init();
      for(i=1; i<=N; i++)
        {
          for(j=1; j<=N; j++)
            {
              scanf("%d",&edge[i][j]);
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&a,&b);
            edge[a][b]=edge[b][a]=0;
        }
      prim();
    }
  return 0;
}



应用2:

Description

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。
 

Input

输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。 
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。 
 

Output

每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.
 

Sample Input

    
    
2 2 10 10 20 20 3 1 1 2 2 1000 1000



反思:这道题和前面的标准模板不一样,每次找党员的时候不见得找得到,所以flag没有值赋给他,故book[flag]=1不合法。

解决方法是:1、在前面先把flag赋为1,这样即使后面为赋值,flag也是1,而我们知道book[1]是等于1的,没有问题。

2、加个判断,如果发现tem值或者flag没变,即仍是inf,则直接返回或者continue。但是。。。。请告诉我!!按理说直接返回就不再执行剩下的while,时间应该比continue快才对,可是我直接返回是31ms,continue是15ms,你在逗我吗!!!!求大神解答


ac代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

#define MaxSize 105
#define inf 0x3f3f3f

int n;
double mp[MaxSize][MaxSize];
double dis[MaxSize];
int book[MaxSize];

struct node
{
  int x, y;
} island[MaxSize];

void init()
{
  for(int i=1; i<=n; i++)
    {
      dis[i]=inf;
      book[i]=0;

      for(int j=1; j<=n; j++)
        {
          mp[i][j]=inf;
        }
    }
}

double cal_dis(int x1, int y1, int x2, int y2)
{
  return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

double prim()
{

  int t=n-1,flag;
  double sum=0;
  dis[1]=0;
  book[1]=1;
  for(int i=1; i<=n; i++)
    {
      if(mp[1][i]<dis[i]&&book[i]==0)
        dis[i]=mp[1][i];
    }
  while(t--)
    {
      //flag=1;
      double tem=inf;
      for(int i=2; i<=n; i++)
        {
          if(dis[i]<tem&&book[i]==0)
            {
              tem=dis[i];
              flag=i;
            }
        }

      if(tem==inf) return inf;
      book[flag]=1;
      sum+=tem;
      for(int i=2; i<=n; i++)
        {
          if(mp[flag][i]<dis[i]&&book[i]==0)
            dis[i]=mp[flag][i];
        }
    }
  return sum;
}

int main()
{
  int T;
  scanf("%d",&T);
  while(T--)
    {
      scanf("%d",&n);

      init();

      for(int i=1; i<=n; i++)
        {
          scanf("%d%d",&island[i].x, &island[i].y);

          for(int j=1; j<=i; j++)
            {
              double distance=cal_dis(island[j].x,island[j].y,island[i].x,island[i].y);
              if(distance>=10&&distance<=1000)
                mp[j][i]=mp[i][j]=distance;
              else
                mp[j][i]=mp[i][j]=inf;
            }
        }

      double ans=prim();

      if(ans<inf)
        printf("%.1lf\n",100*ans);
      else
        printf("oh!\n");
    }
  return 0;
}//FROM CJZ


另外,一个wa代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

#define MaxSize 105
#define inf 0x3f3f3f

int n;
double mp[MaxSize][MaxSize];
double dis[MaxSize];
int book[MaxSize];

struct node
{
  int x, y;
} island[MaxSize];

void init()
{
  for(int i=1; i<=n; i++)
    {
      dis[i]=inf;
      book[i]=0;

      for(int j=1; j<=n; j++)
        {
          mp[i][j]=inf;
        }
    }
}

double cal_dis(int x1, int y1, int x2, int y2)
{
  return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

double prim()
{

  int t=n-1,flag;
  double sum=0;
  dis[1]=0;
  book[1]=1;
  for(int i=1; i<=n; i++)
    {
      if(mp[1][i]<dis[i]&&book[i]==0)
        dis[i]=mp[1][i];
    }
  while(t--)
    {
      flag=1;
      double tem=inf;
      for(int i=2; i<=n; i++)
        {
          if(dis[i]<tem&&dis[i]>=10&&dis[i]<=1000&&book[i]==0)
            {
              tem=dis[i];
              flag=i;
            }
        }

      if(tem==inf) return inf;//31ms
      //if(tem==inf) continue;  //15ms

      book[flag]=1;
      sum+=tem;
      for(int i=2; i<=n; i++)
        {
          if(mp[flag][i]<dis[i]&&book[i]==0)
            dis[i]=mp[flag][i];
        }
    }
  return sum;
}

int main()
{
  int T;
  scanf("%d",&T);
  while(T--)
    {
      scanf("%d",&n);

      init();

      for(int i=1; i<=n; i++)
        {
          scanf("%d%d",&island[i].x, &island[i].y);

          for(int j=1; j<=i; j++)
            {
              mp[j][i]=mp[i][j]=cal_dis(island[j].x,island[j].y,island[i].x,island[i].y);
            }
        }

      double ans=prim();

      if(ans<inf)
        printf("%.1lf\n",100*ans);
      else
        printf("oh!\n");
    }
  return 0;
}//FROM CJZ

为什么把长度判断放在prim里面就会wa?想不通,求看到这个问题的大神答疑,非常感谢

==============================================================================================================================

Description

国防部(DND)要用无线网络连接北部几个哨所。两种不同的通信技术被用于建立网络:每一个哨所有一个无线电收发器,一些哨所将有一个卫星频道。
任何两个有卫星信道的哨所可以通过卫星进行通信,而不管他们的位置。同时,当两个哨所之间的距离不超过D时可以通过无线电通讯,D取决于对收发器的功率。功率越大,D也越大,但成本更高。出于采购和维修的方便,所有哨所的收发器必须是相同的;那就是说,D值对每一个哨所相同。
 
你的任务是确定收发器的D的最小值。每对哨所间至少要有一条通信线路(直接或间接)。

Input

输入的第一行是测试数据的数量N。
每组测试数据的第一行包含卫星频道的数量S(1 < = S < = 100)和哨所的数量P(S < P < = 500)。接下来的P行,给出以公里为单位的每个哨所的坐标(x,y)( 坐标为0到10000之间的整数)。

Output

对于每组测试数据,输出一行,输出收发器的D的最小值。精确到小数点后两位。

Sample Input

1
2 4
0 100
0 300
0 600
150 750

Sample Output

212.13


代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;

#define MaxSize 505
#define inf 0x3f3f3f

int s,p,cnt;
int pre[MaxSize];

double cal_dis(int x1, int y1, int x2, int y2)
{
  return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}

struct node1
{
  int x, y;
} station[MaxSize];

struct node2
{
  int x, y;
  double len;
} mp[MaxSize*MaxSize];

bool cmp(node2 a, node2 b)
{
  return a.len<b.len;
}

int find(int a)
{
  int a1=a;
  while(pre[a1]!=a1)
    a1=pre[a1];

  int a2=a;
  while(pre[a2]!=a2)
    {
      int tem=pre[a2];
      pre[a2]=a1;
      a2=tem;
    }
  return a1;
}

void kruskal()
{
  int flag=0;

  for(int i=0; i<p; i++)
    pre[i]=i;

  for(int i=0; i<cnt; i++)
    {
      int x=find(mp[i].x);
      int y=find(mp[i].y);
      if(x!=y)
        {
          pre[x]=y;
          flag++;
          if(flag==p-s)
            {
              printf("%.2lf\n",mp[i].len);
              break;
            }
        }
    }
}

int main()
{
  int N;
  scanf("%d",&N);
  while(N--)
    {
      cnt=0;
      scanf("%d%d",&s,&p);
      for(int i=0; i<p; i++)
        {
          scanf("%d%d",&station[i].x,&station[i].y);
          for(int j=0; j<i; j++)
            {
              mp[cnt].len=cal_dis(station[i].x,station[i].y,station[j].x,station[j].y);
              mp[cnt].x=i;
              mp[cnt].y=j;
              cnt++;
            }
        }

      sort(mp,mp+cnt,cmp);

      kruskal();
    }
  return 0;
}//FROM CJZ

这里有个东西很奇怪,输出用%.2lf交G++就wa,%.2lf交C++就ce,只有%.2f交G++才a,为什么为什么为什么

不过这种思路貌似有问题,但是没时间仔细看了,以后花时间来看。

http://www.lxway.com/809955254.htm

===========================================================================================================================

Description

The Borg is an immensely powerful race of enhanced humanoids from the delta quadrant of the galaxy. The Borg collective is the term used to describe the group consciousness of the Borg civilization. Each Borg individual is linked to the collective by a sophisticated subspace network that insures each member is given constant supervision and guidance. 

Your task is to help the Borg (yes, really) by developing a program which helps the Borg to estimate the minimal cost of scanning a maze for the assimilation of aliens hiding in the maze, by moving in north, west, east, and south steps. The tricky thing is that the beginning of the search is conducted by a large group of over 100 individuals. Whenever an alien is assimilated, or at the beginning of the search, the group may split in two or more groups (but their consciousness is still collective.). The cost of searching a maze is definied as the total distance covered by all the groups involved in the search together. That is, if the original group walks five steps, then splits into two groups each walking three steps, the total distance is 11=5+3+3.

Input

On the first line of input there is one integer, N <= 50, giving the number of test cases in the input. Each test case starts with a line containg two integers x, y such that 1 <= x,y <= 50. After this, y lines follow, each which x characters. For each character, a space `` '' stands for an open space, a hash mark ``#'' stands for an obstructing wall, the capital letter ``A'' stand for an alien, and the capital letter ``S'' stands for the start of the search. The perimeter of the maze is always closed, i.e., there is no way to get out from the coordinate of the ``S''. At most 100 aliens are present in the maze, and everyone is reachable.

Output

For every test case, output one line containing the minimal cost of a succesful search of the maze leaving no aliens alive.

Sample Input

2
6 5
##### 
#A#A##
# # A#
#S  ##
##### 
7 7
#####  
#AAA###
#    A#
# S ###
#     #
#AAA###
#####  

Sample Output

8
11


这是一道出题思路很不错的题

代码(别人的):

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<algorithm>
#include <queue>
using namespace std;

#define inf 0x3f3f3f
#define MaxSize 105

int x[4]= {0,0,1,-1};
int y[4]= {1,-1,0,0};
int dis[MaxSize][MaxSize],low[MaxSize],node[MaxSize][MaxSize];
char map[MaxSize][MaxSize];
bool visit[MaxSize][MaxSize];
int n,m,node_sum;

struct Node
{
  int x,y,dis;
};

void BFS(int i, int j)
{
  memset(visit, false, sizeof(visit));
  visit[i][j]=true;
  Node b = {i, j, 0};
  queue<Node> N;
  N.push(b);
  while(!N.empty())
    {
      Node front = N.front();
      if(node[ front.x ][ front.y ])
        dis[ node[b.x][b.y] ][ node[front.x][front.y] ] = front.dis;
//当时脑子卡了一下没理解,总觉得这里应该更新最小值。因为队列里每一个点都是一步一步走的,如果有一个点走到字母了,那它一定是第一个到的,而此时将其标记,其他点就不会走到这里了。
      N.pop();
      for(i=0; i<4; i++)
        {
          int xx = front.x+x[i];
          int yy = front.y+y[i];
          if(xx>=1&&xx<=n && yy>=1&&yy<=m)
            if(map[xx][yy]!='#' && !visit[xx][yy])
              {
                visit[xx][yy] = true;
                Node t = {xx, yy, front.dis+1};
                N.push(t);
              }
        }
    }
}
int Prim()
{
  int s=1,i,count=1,prim_sum=0,t;
  bool flag[MaxSize]= {false};
  flag[s] = true;
  for(i=1; i<=node_sum; i++)
    low[i] = inf;
  while(count < node_sum)
    {
      int min_dis = inf;
      for(i=1; i<=node_sum; i++)
        {
          if(!flag[i] && low[i]>dis[s][i])
            low[i] = dis[s][i];
          if(!flag[i] && low[i]<min_dis)
            {
              min_dis = low[i];
              t = i;
            }
        }
      s = t;
      count++;
      flag[s] = true;
      prim_sum += min_dis;
    }
  return prim_sum;
}
void init()
{
  memset(map, '#', sizeof(map));
  memset(dis, 0, sizeof(dis));
  memset(node, 0,sizeof(node));
  memset(dis, inf,sizeof(dis));
  node_sum = 0;
}
int main()
{
  int T,i,j;
  char temp[MaxSize];
  scanf("%d", &T);
  while(T--)
    {
      init();
      scanf("%d%d",&m,&n);
        gets(temp);
      for(i=1; i<=n; i++)
        {
          gets(map[i]);
          for(j=1; j<=m; j++)
            {
              if(map[i][j]=='A' || map[i][j]=='S')
                node[i][j]=++node_sum;
            }
        }
      for(i=1; i<=n; i++)
        for(j=1; j<=m; j++)
          {
            if(node[i][j])
              BFS(i,j);
          }
      printf("%d\n", Prim());
    }
  return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值