codevs1002搭桥(建图+Prim)

/*
先来个灌水法 然后建图跑最小生成树
注意观察题目中的规则 a[1][i]!=a[1][j]&&abs(a[2][i]-a[2][j])<=1
建图的时候可以每一个建筑物都看成一个点 然后计算需要几个桥
 同一个城市的不用桥 
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int n,m,tot,g[1001][1001],a[3][1001],minn[10001],f[10001],sum,bb;
char s[101][101];
int xx[9]={0,0,0,1,1,1,-1,-1,-1};//枚举8个方向 
int yy[9]={0,1,-1,-1,0,1,-1,0,1};
void Dfs(int x,int y)
{
    s[x][y]=tot+48;
    int i,j,ox,oy;
    for(i=1;i<=8;i++)//枚举8个方向 
    {
      ox=x+xx[i];oy=y+yy[i];
      if(ox>0&&ox<=n&&oy>0&&oy<=m&&s[ox][oy]=='#')
        Dfs(ox,oy);
    }
}
int main()
{
    cin>>n>>m;
    int i,j,k,l;
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
        cin>>s[i][j];
    for(i=1;i<=n;i++)
      for(j=1;j<=m;j++)
        if(s[i][j]=='#')//统计城市个数 
          {
            tot++;
              Dfs(i,j);
          }
    cout<<tot<<endl;
    memset(g,1,sizeof(g));
    tot=0;//建筑物数量 
    for(i=1;i<=n;i++)
      {
          for(j=1;j<=m;j++)
            if(s[i][j]!='.')//记录每个建筑物的信息 
              {
                tot++;
                a[1][tot]=i;//横坐标 
                a[2][tot]=j;//纵坐标 
            }
      }
    for(i=1;i<=tot;i++)//建图(每个点都建 属于一个城市的不同桥) 
      for(j=i+1;j<=tot;j++)
        {
          if(a[1][i]!=a[1][j]&&abs(a[2][i]-a[2][j])<=1)//如果符合连桥的条件 
            {
              g[i][j]=abs(a[1][i]-a[1][j])-1;
              g[j][i]=g[i][j];
            }
          else if(a[2][i]!=a[2][j]&&abs(a[1][i]-a[1][j])<=1)
            {
              g[i][j]=abs(a[2][i]-a[2][j])-1;
              g[j][i]=g[i][j];
            }
        }
    memset(minn,1,sizeof(minn));
    minn[1]=0;
    for(i=1;i<=tot;i++)//跑 Prim 
      {
          k=0;
          for(j=1;j<=tot;j++)
            if(f[j]==0&&minn[j]<minn[k])
              k=j;
          f[k]=1;
          for(j=1;j<=tot;j++)
            if(f[j]==0&&minn[j]>g[k][j])
              minn[j]=g[k][j];
      }
    for(i=1;i<=tot;i++)
      {
          if(minn[i]!=0&&minn[i]<1000000)
          {
              bb++;//统计桥的个数 
              sum=sum+minn[i];//累加桥的长度 
          }
      }
    cout<<endl<<bb<<" "<<sum;
    return 0;
}
原文地址:https://www.cnblogs.com/yanlifneg/p/5424182.html