ZOJ - 3781 缩点+最短路径

题目大意:字符一样并且相邻的即为连通。每次可翻转一个连通块X(O)的颜色,问至少改变几次使得图上所有字符都相等

题目思路:每次操作都将本身所在的连通块与和自己相邻的不同颜色的连通块变成同一种颜色,也就是变成一个连通块了,那么要使n次操作后全部变成一样的颜色,也就是从某点出发到达其余所有点。

所以,dfs把连通块缩成点,然后相邻的连通块之间建边,枚举以每个点为根的情况,求最短路。

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn=2000;
int n,m;
char mapp[50][50];
int vis[50][50];
int viss[maxn];
int belong[50][50];
int mmp[maxn][maxn];
struct node
{
    int x,y;
}headd,tail;
struct edge
{
    int v,nxt;
}edge[20000];
int cnt=0;
int head[20000];
void add_edge(int u,int v)
{
    edge[cnt].v=v;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
}
int dir[4][2]={0,1,1,0,0,-1,-1,0};
int block=0;
void bfs(int x,int y)
{
    headd.x=x;
    ++block;
    headd.y=y;
    vis[x][y]=1;
    queue<node>q;
    while(!q.empty())q.pop();
    q.push(headd);
    while(!q.empty())
    {
        headd=q.front();
        q.pop();
        belong[headd.x][headd.y]=block;
        for(int i=0;i<4;i++)
        {
            tail.x=headd.x+dir[i][0];
            tail.y=headd.y+dir[i][1];
            if(tail.x<=n&&tail.y<=m&&tail.x>=1&&tail.y>=1)
            {
                if(vis[tail.x][tail.y]==0&&mapp[tail.x][tail.y]==mapp[x][y])
                {
                    q.push(tail);
                    vis[tail.x][tail.y]=1;
                }
            }
        }
    }
}
struct nodee
{
    int distance,point;
    nodee(){}
    nodee(int _point,int _distance)
    {
        point=_point;
        distance=_distance;
    }
    friend bool operator <(nodee aa,nodee bb)
    {
        return aa.distance>bb.distance;
    }
};
int dis[maxn];
int maxx=0;
void zyz(int u)
{
    for(int i=1;i<=block;i++)
    {
        dis[i]=0x3f3f3f3f;
        viss[i]=0;
    }
    dis[u]=0;
    priority_queue<nodee>q;
    while(!q.empty())
        q.pop();
    q.push(nodee(u,dis[1]));
    while(!q.empty())
    {
        nodee now;
        now=q.top();
        q.pop();
        if(viss[now.point]==1)
        {
            continue;
        }
        viss[now.point]=1;
        for(int i=head[now.point];i!=-1;i=edge[i].nxt)
        {
            int v=edge[i].v;
            if(viss[v]==0)
            {
                if(dis[v]>dis[now.point]+1)
                {
                    dis[v]=dis[now.point]+1;
                    q.push(nodee(v,dis[v]));
                }
            }
        }
    }
    maxx=0;
    for(int i=1;i<=block;i++)
    {
        maxx=max(maxx,dis[i]);
    }
}
int main ()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(mapp,0,sizeof(mapp));
        memset(vis,0,sizeof(vis));
        memset(viss,0,sizeof(viss));
        memset(belong,0,sizeof(belong));
        memset(mmp,0,sizeof(mmp));
        block=0;
        maxx=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                scanf(" %c",&mapp[i][j]);
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(vis[i][j]==0)
                {
                    bfs(i,j);
                }
            }
        }
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                for(int k=0;k<4;k++)
                {
                    int tx,ty;
                    tx=i+dir[k][0];
                    ty=j+dir[k][1];
                    if(tx>=1&&ty>=1&&tx<=n&&ty<=m)
                    {
                        if(belong[i][j]!=belong[tx][ty])
                        {
                            mmp[belong[i][j]][belong[tx][ty]]=1;
                            mmp[belong[tx][ty]][belong[i][j]]=1;
                        }
                    }
                }
            }
        }
        for(int i=1;i<=block;i++)
        {
            for(int j=1;j<=block;j++)
            {
                if(mmp[i][j]==1)
                {
                    add_edge(i,j);
                }
            }
        }
        int answer=0x3f3f3f3f;
        for(int i=1;i<=block;i++)
        {
            zyz(i);
            answer=min(answer,maxx);
        }
        printf("%d\n",answer);  
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值