寒假Day31:CSU1508地图的四着色bfs+dfs

题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1508

Description:

有一个R行C列的网格地图,每个国家是一个四连通区域。你的任务是用红,绿,蓝,黄四种颜色给地图着色,使得相邻国家的颜色不同。
一个人着色比较无趣,所以你想请女朋友陪你一起涂——你涂红绿,她涂蓝黄。当然,绅士是不会让让女朋友受累的,所以她最多只需涂5个国家(恰好5个也行)。
你的任务是统计有多少种着色的方法。注意,每个颜色都至少要用一次。

Input

输入包含不超过100组数据。每组数据第一行为两个整数R和C (1<=R,C<=20),即网格的行数和列数。以下R行每行C个大写字母。相同字母所组成的四连通区域代表一个国家。输入保证国家数目不超过30,并且大多数测试点的国家数都比较小。

Output

对于每组数据,输出测试点编号和着色方案数。

Sample Input

2 4
AABB
BBAA
1 5
ABABA
4 7
AABAABB
ABBCCCB
BBAACBB
CCABBAC

Sample Output

Case 1: 24
Case 2: 144
Case 3: 3776

Hint

Source  湖南省第十届大学生计算机程序设计竞赛

 

思路:

1、

先用bfs1给每一点进行标号,用第一组样例来说

AABB

BBAA,

标完号之后就变成了

1122

3344

2、

用bfs2把相邻的国家连接起来,用邻接表存储,vector可以勉强水过

用上面那组例子,连接好之后就变成

1-2-3

2-1-4

3-1-4

3、

每一种可行情况ans++,最后的结果*4不会超时,因为有四种可能,AC、AD、BC、BD,男生先染、女生后染。

邻接表过的,很多处理细节需要注意,还得一遍遍尝试。

AC代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<queue>
using namespace std;
typedef long long ll;

char a[25][25];
int n,m,num,tot,ans;
bool book1[35][35],book2[35][35];
int id[25][25],head[35],color[35];
int to[4][2]= {{0,1},{0,-1},{1,0},{-1,0}};

struct node
{
    int x,y;
} p,q;

struct E
{
    int v,nextt;
} e[1005];

void add(int u,int v)
{
    e[tot].v=v;
    e[tot].nextt=head[u];
    head[u]=tot++;
}

void bfs1(int x,int y)
{
    id[x][y]=num;//横纵坐标
    p.x=x;
    p.y=y;
    queue<node>Q;
    Q.push(p);
    while(!Q.empty())
    {
        q=Q.front();
        Q.pop();
        for(int i=0; i<4; i++)
        {
            p=q;
            p.x+=to[i][0];
            p.y+=to[i][1];
            if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m&&a[p.x][p.y]==a[q.x][q.y]&&id[p.x][p.y]==0)
            {
                id[p.x][p.y]=num;
                Q.push(p);
            }
        }
    }
}

void bfs2(int x,int y)
{
    queue<node>Q;
    p.x=x;
    p.y=y;
    Q.push(p);
    while(!Q.empty())
    {
        q=Q.front();
        Q.pop();
        book1[q.x][q.y]=1;
        for(int i=0; i<4; i++)
        {
            p=q;
            p.x+=to[i][0];
            p.y+=to[i][1];
            //if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m&&book1[p.x][p.y]==0)
            if(p.x>=0&&p.x<n&&p.y>=0&&p.y<m)
            {
                if(id[p.x][p.y]!=id[q.x][q.y])
                {
                    //add(id[p.x][p.y],id[q.x][q.y]);
                    //add(id[q.x][q.y],id[p.x][p.y]);
                    book2[id[p.x][p.y]][id[q.x][q.y]]=1;
                    book2[id[q.x][q.y]][id[p.x][p.y]]=1;
                    continue;
                    //  Q.push(p);
                }
                if(book1[p.x][p.y]==0)
                    Q.push(p);//MLE
            }
//            if(book1[p.x][p.y]==0)
//            Q.push(p);//MLE
        }
    }
}

int check(int s,int k)
{
    //不能传入i、k
    for(int i=head[s]; i!=-1; i=e[i].nextt)
    {
        if(color[e[i].v]==k)
            return 0;
    }
    return 1;
}

void dfs(int i,int a1,int a2,int a3,int a4)//涂到第几个城市,四种颜色分别涂了几个
{
    if(num+1==i)
    {
        if(a1&&a2&&a3&&a4)
            ans++;
        return ;
    }//只能写成这样,改了一下要么RT要么WA

    color[i]=0;
    if(check(i,0))
        dfs(i+1,a1+1,a2,a3,a4);//第一种颜色
    
    color[i]=1;
    if(a1&&check(i,1))
        dfs(i+1,a1,a2+1,a3,a4);//
    
    color[i]=2;
    if(a3+a4<5&&check(i,2))
        dfs(i+1,a1,a2,a3+1,a4);//
        
    color[i]=3;
    if(a3&&a3+a4<5&&check(i,3))
        dfs(i+1,a1,a2,a3,a4+1);//
}

int main()
{
    int t=1;
    while(~scanf("%d %d",&n,&m))
    {
        memset(id,0,sizeof(id));
        memset(book1,0,sizeof(book1));
        memset(book2,0,sizeof(book2));
        memset(head,-1,sizeof(head));
        for(int i=0; i<n; i++)
            scanf("%s",a[i]);//注意一下
        num=0;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                if(id[i][j]==0)
                {
                    num++;
                    bfs1(i,j);
                }
            }
        }//vs bfs1(0,0)

        tot=0;
        for(int i=0; i<n; i++)
        {
            for(int j=0; j<m; j++)
            {
                if(book1[i][j]==0)
                    bfs2(i,j);
            }
        }


//        for(int i=0; i<n; i++)
//        {
//            for(int j=0; j<m; j++)
//            {
//                if(book[i][j]==0)
//                    bfs2(i,j);
//            }
//        }
        for(int i=1; i<=num; i++)
        {
            for(int j=1; j<i; j++)//到n也WA
            {
                if(book2[i][j]==1)
                    add(i,j);
            }
        }
        ans=0;
        dfs(1,0,0,0,0);
        printf("Case %d: %d\n",t++,ans*4);
    }
    return 0;
}

Thinking

反正这题一点也不好写,稍微改改就要错,提交了二十几,写完我就看英语去~~~

我觉得难的题我过了也没啥用,

最近天天凌晨睡觉,一个代码扣几个小时,即使再写也不一定能过,

感觉还是只能做简单题,

我还是去刷cf的简单题叭~~~

再这样下去,一事无成,时间也耗在着,几个小时做一道题,好几天都这样,又和以前一样了~

还是要加油鸭

原文地址:https://www.cnblogs.com/OFSHK/p/12321520.html