POJ

来源:互联网 发布:mac 中文字幕乱码 编辑:程序博客网 时间:2024/05/21 01:44

题目大意:

多组测试实例(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 0x3f3f3f3fusing 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 0x3f3f3f3fusing 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号点为Sint 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;    }}/*86 5##### #A#A### # A##S  ####### 7 7#####  #AAA####    A## S ####     ##AAA########  6 5##### #A#A### # A##S  ####### 7 7#####  #   ####     ## S ####     ##   ########  */

后记:

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

0 0
原创粉丝点击