题目大意:

多组测试实例(50),每组测试给你一个图(50*50),然后给你一个S点和若干个A点(100)。一个小人从点S开始,他在S点或者A点可以分别成多个小人。现在他要访问到每个点,让你求出他要走的最少的距离。
注意: 只有当borg在S点或者找到一个alien之后,它们可以继续以分成若干的小队伍。

思路:

只有在S和A可以分裂,这表示了什么?这表示这个图(无向),每个顶点(A或S)可以有多个边!然后想到最小生成树,但是每一对点之间的距离怎么计算呢,我觉得就是用广搜确定出来的,就是他们之间的距离(因为有距离)。
这个复杂度可能不小,得算一下:
100个点,两个之间一搜索,100*101/2=5050个搜索,每个图50*50=2500个点(如果全部都要访问一次的话),每组测试实例确定距离需要5000*2500=12,500,000。50组:50* 12,500,000=625,000,000。当然这个是最坏的情况。
然后问题就简化成一个图,求它的最小生成树。我感觉这个图边应该很多,如果用prim枚举点的话,应该是比较划算的。但是仔细一想,因为求最小生成树的过程和n次广搜的过程是并列的,所以慢一点也没关系,反正肯定比n次广搜快,我就写的kruckal。
这次要是还不ac我就要吐血了~

代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
#define maxxy 55
#define maxn 105
#define inf 0x3f3f3f3f


using namespace std;
int n;
int map[maxxy][maxxy]={0};
int dis[maxn][maxn]={0};
int num[maxxy][maxxy];
struct point
{
    int x;
    int y;
}a[maxn];
struct edge
{
    int s;int e;int v;
}b[maxn*maxn]; 
int x,y;
int move[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int boss[maxn]={0};

int find(int x)
{
    return boss[x]==x?x:boss[x]=find(boss[x]);
}

void match(int a,int b)
{
    int fa=find(a);
    int fb=find(b);
    boss[fa]=fb;
    return;
}


void ceshi1()
{
    for(int i=1;i<=y;i++)
    {
        for(int j=1;j<=x;j++)
        {
            cout<<map[i][j];
        }
        cout<<endl;
    }
}
void ceshi2()
{
    for(int i=1;i<=n;i++)
    {
        cout<<a[i].x<<" "<<a[i].y<<endl;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<dis[i][j]<<" ";
        }
        cout<<endl;
    }
}
bool my_cmp(edge a,edge b)
{
    return a.v<b.v;
}
void bfs(int k)//从k号点开始广搜 
{
    bool vis[maxxy][maxxy]={0};
    int v[maxxy][maxxy]={0};
    queue<point>q;
    q.push(a[k]);
    vis[a[k].x][a[k].y]=1;
    v[a[k].x][a[k].y]=0;
    while(!q.empty())
    {
        for(int i=0;i<4;i++)
        {
            point l;
            l.x=q.front().x+move[i][1];
            l.y=q.front().y+move[i][0];
            if(l.x>x||l.x<1||l.y>y||l.y<1)continue;
            if(vis[l.x][l.y])continue;
            if(map[l.x][l.y]==1)continue;
            v[l.x][l.y]=v[q.front().x][q.front().y]+1;
            q.push(l);
            vis[l.x][l.y]=1;
            if(map[l.x][l.y]==2)
            {
                dis[k][num[l.x][l.y]]=v[l.x][l.y];
            }
        }
        q.pop();
    }
}
int my_kruskal()
{
    for(int i=0;i<=n;i++)
    {
        boss[i]=i;
    }
    int s=0;
    int num=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=i+1;j<=n;j++)
        {
            num++;
            b[num].s=i;
            b[num].e=j;
            b[num].v=dis[i][j];
        }
    }
    sort(b+1,b+num+1,my_cmp);
    for(int i=1;i<=num;i++)
    {
        //cout<<find(b[i].s)<<" "<<find(b[i].e)<<endl;
        if(find(b[i].s)==find(b[i].e))continue;
        match(b[i].s,b[i].e);
        s+=b[i].v;
    }
    return s;
}
int main()
{
    int test;
    scanf("%d",&test);
    while(test--)
    {
        char c;
        scanf("%d %d",&x,&y);
        while(c!='\n')
        {
            scanf("%c",&c);
        }
        n=1;
        memset(map,0,sizeof(map));
        memset(dis,0x3f,sizeof(dis));
        for(int i=1;i<=y;i++)
        {
            for(int j=0;j<=x;j++)//墙1,外星人2,空位0 
            {
                scanf("%c",&c);
                if(c=='#')map[j+1][i]=1;
                if(c=='A')
                {
                    map[j+1][i]=2;
                    n++;
                    a[n].x=j+1;a[n].y=i;
                    num[j+1][i]=n;
                }
                if(c=='S')
                {
                    map[j+1][i]=2;
                    a[1].x=j+1;a[1].y=i;
                    num[j+1][i]=1;
                }
            }
        }
        //ceshi1();
        for(int i=1;i<=n;i++)
        {
            bfs(i);
        }
        //ceshi2();
        cout<<my_kruskal()<<endl;
    }
}

另外附上以前寒假时候写的错的代码,也许有一天我真的会去查查以前是怎么错的吧,主要是实在不舍得删啊。这一段你们就不要看了。。。。

#include<iostream>
#include<stdio.h>
#include<queue>
#include<math.h>
#include<string.h>
#define xy_max 65
#define N 120
#define inf 0x3f3f3f3f
using namespace std;
struct point
{
    int x;
    int y;
}poi[N]={0};
int x,y; 
int n;//点的个数 
char map[xy_max][xy_max];
int dis[N][N]={0};//1号点为S
int deep[xy_max][xy_max]={0};//点ij到原点的距离 
bool vis[xy_max][xy_max]={0};
int mincost[N]={0};
bool inside[N]={0};
void input()
{
    memset(map,0,sizeof(map));
    n=2;
    cin>>x>>y;
    char c;
    scanf("%c",&c);//注意要读取数字行的换行符 
    for(int i=1;i<=y;i++)
    {
        for(int j=1;j<=x+1;j++)
        {
            scanf("%c",&map[i][j]);
            if(map[i][j]=='S')
            {
                poi[1].x=j;
                poi[1].y=i;
            }
            if(map[i][j]=='A')
            {
                poi[n].x=j;
                poi[n].y=i;
                n++;
            }
        }
    }
}

void bfs(int v)//对v号点进行dfs 
{
    point k=poi[v];
    int fx[4]={-1,0,1,0};
    int fy[4]={0,1,0,-1};
    memset(deep,0,sizeof(deep));
    memset(vis,0,sizeof(vis));
    queue<int>qx;
    queue<int>qy;
    qx.push(k.x);
    qy.push(k.y);
    deep[k.y][k.x]=0;
    vis[k.y][k.x]=1;
    while(1)
    {

        if(qx.empty()&&qy.empty())break;
        for(int i=0;i<4;i++)//向四个方向扩展 
        {
            if(qy.front()+fy[i]<=0||qy.front()+fy[i]>y||qx.front()+fx[i]<=0||qx.front()+fx[i]>x)continue;
            if(vis[qy.front()+fy[i]][qx.front()+fx[i]])continue;
            if(map[qy.front()+fy[i]][qx.front()+fx[i]]=='#')continue;
            deep[qy.front()+fy[i]][qx.front()+fx[i]]=deep[qy.front()][qx.front()]+1;
            vis[qy.front()+fy[i]][qx.front()+fx[i]]=1;
            qx.push(qx.front()+fx[i]);
            qy.push(qy.front()+fy[i]);
        }
        qx.pop();
        qy.pop();
    }
    for(int i=1;i<n;i++)
    {
        dis[v][i]=deep[poi[i].y][poi[i].x];
    }

} 

void ceshi1()
{
    for(int i=1;i<n;i++)
    {
        cout<<poi[i].y<<poi[i].x; 
        cout<<endl;
    }
} 
void ceshi2()
{
    for(int i=1;i<n;i++)
    {
        for(int j=1;j<n;j++)cout<<dis[i][j];
        cout<<endl;
    }
}
int numout()
{
    int s=0;
    for(int i=1;i<n;i++)
    {
        if(inside[i]==0)s++;
    }
    return s;
}
int my_prim()
{
    int v=1;
    int s=0;
    memset(inside,0,sizeof(inside));
    inside[1]=1;
    for(int i=1;i<n;i++)
    {
        mincost[i]=dis[1][i];
    }
    while(1)
    {
        if(numout()==0)break;
        int min=inf;
        for(int i=1;i<n;i++)//找到即将入图的点号v 
        {
            if(inside[i]==1)continue;
            if(min>mincost[i])
            {
                min=mincost[i];
                v=i;
            }
        }
        s=s+min;
        inside[v]=1;
        for(int i=1;i<n;i++)
        {
            if(inside[i]==1)continue;
            if(mincost[i]>dis[v][i])
            {
                mincost[i]=dis[v][i];
            }
        } 

    }
    return s;
}


int main()
{
    int cs=0;
    cin>>cs;
    while(cs--)
    {
        input();
        for(int i=1;i<n;i++)bfs(i);
        //ceshi2();
        //ceshi1();
        cout<<my_prim()<<endl;
    }
}
/* 8 6 5 ##### #A#A## # # A# #S ## ##### 7 7 ##### #AAA### # A# # S ### # # #AAA### ##### 6 5 ##### #A#A## # # A# #S ## ##### 7 7 ##### # ### # # # S ### # # # ### ##### */

后记:

出问题可以先偷偷看下discuss。这道题输入数据中输入地图大小的两个数所在的那一行,两个数后面可能会有若干空格。