csu1508 地图的四着色(剪枝+BFS DFS)

本文探讨了一种特定的地图染色问题,通过DFS/BFS算法进行城市区域划分,并利用邻接矩阵与邻接表来优化搜索过程。最终采用深度优先搜索实现染色方案的枚举。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:中文题

思路:首先男女各人用两种颜色,那么用A不用B和用B不用A时候的方案数是等价的,那么我们可以强行固定男先用A染色,女生先用C染色,最后方案数*4就是最后总的方案数。先用DFS/BFS把相同的城市标号,然后再次DFS/BFS把图的领接矩阵构造出来,然后再遍历一遍把邻接表构造出来。

           使用邻接表是因为可以快速地查找与它相邻的城市,而先构造邻接矩阵是因为要判重,然后直接固定一下他们染色的顺序就直接爆搜就可以了。实现起来还是有挺多细节的吧。

吐槽:用vector 19964MS卡过去了,自己实现的前向星10284MS。。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
char mp[35][35];
int vis[35][35],flag[35][35],mapp[35][35];
//vector<int>e[35];
struct Edge
{
	int v,nxt;
}edge[1005];
int head[35],num;
void add(int u,int v)
{
	edge[num].v=v;
	edge[num].nxt = head[u];
	head[u]=num++;
}

int color[35];
int cnt=0;
long long ans=0;
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
int r,c;
void bfs(int x,int y)
{
	++cnt;
	queue<pair<int,int> >q;
	q.push(make_pair(x,y));
	while(!q.empty())
	{
		pair<int,int> t = q.front();
		q.pop();
		vis[t.first][t.second]=cnt;
        for(int i = 0;i<4;i++)
		{
			int dx = t.first +dir[i][0];
			int dy = t.second+dir[i][1];
			if(dx<0 || dx>=r || dy<0||dy>=c)continue;
			if(vis[dx][dy] || mp[dx][dy]!=mp[t.first][t.second])continue;
			q.push(make_pair(dx,dy));
		}
	}
}
void bfs1(int x,int y)
{
    queue<pair<int,int> >q;
	q.push(make_pair(x,y));
	while(!q.empty())
	{
		pair<int,int> t = q.front();
		q.pop();
		flag[t.first][t.second]=1;
        for(int i = 0;i<4;i++)
		{
			int dx = t.first +dir[i][0];
			int dy = t.second+dir[i][1];
			if(dx<0 || dx>=r || dy<0||dy>=c)continue;
			if(flag[dx][dy])continue;
			if(vis[t.first][t.second]!=vis[dx][dy])
			{
				mapp[vis[t.first][t.second]][vis[dx][dy]]=mapp[vis[dx][dy]][vis[t.first][t.second]]=1;
				continue;
			}
			q.push(make_pair(dx,dy));
		}
	}
}

bool check(int u,int co)
{
	for(int i = head[u];i!=-1;i=edge[i].nxt)
		if(color[edge[i].v]==co)return 0;
	return 1;
	//for(int i = 0;i<e[u].size();i++)
	//	if(color[e[u][i]]==co)return 0;
//	return 1;
}

//当前第几个城市 A用了几个 B用了几个 C用了几个 D用了几个
void dfs(int pos,int a,int b,int c,int d)
{
     if(pos==cnt+1)
	 {
		 if(a&&b&&c&&d)ans++;
		 return;
	 }
     color[pos]=0;
	 if(check(pos,0))dfs(pos+1,a+1,b,c,d);
	 color[pos]=1;
	 if(check(pos,1) && a)dfs(pos+1,a,b+1,c,d);
	 color[pos]=2;
	 if(check(pos,2) && c+d<5)dfs(pos+1,a,b,c+1,d);
     color[pos]=3;
	 if(check(pos,3) && c+d<5 && c)dfs(pos+1,a,b,c,d+1);
}

void init()
{
     memset(vis,0,sizeof(vis));
	 memset(flag,0,sizeof(flag));
	 memset(color,0,sizeof(color));
//	 for(int i = 0;i<35;i++)e[i].clear();
	 memset(mp,0,sizeof(mp));
	 memset(mapp,0,sizeof(mapp));
	 ans = 0;
	 cnt = 0;
	 memset(head,-1,sizeof(head));
	 num=0;
}
int cas = 1;
int main()
{
	 while(scanf("%d%d",&r,&c)!=EOF)
	 {
		 init();
          for(int i = 0;i<r;i++)scanf("%s",mp[i]);
		  //get id
		  for(int i = 0;i<r;i++)
			  for(int j = 0;j<c;j++)
				  if(!vis[i][j])bfs(i,j);

		  for(int i = 0;i<r;i++)
			  for(int j = 0;j<c;j++)
				  if(!flag[i][j])bfs1(i,j);

         for(int i = 1;i<=cnt;i++)
			 for(int j = 1;j<i;j++)
				 if(i!=j && mapp[i][j])
				 {
					 add(i,j);
			//		 e[i].push_back(j);
				 }

         dfs(1,0,0,0,0);

		 printf("Case %d: %lld\n",cas++,ans*4);
	 }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值