UVA - 10160 Servicing Stations 剪枝+回溯

题目大意:给你N个点,M个相连信息,求最少要在几个点放置服务器才能让所有的点都被覆盖到,放置服务器的点只能把本身和相邻的点覆盖

解题思路:点只存在放还是不放置服务器两中选择,不剪枝的话就会超时,毕竟是2^35,剪枝的话,包括三种情况

1.当前放置服务器的点大于需要放置的最小值,既然大于了最优情况了,就不必要继续在递归下去了

2.放置服务器的点不影响其他点的状态,那么放置该点就没有意义了,因为图联通的

3.出现前面有点无法被覆盖的情况,比如当前已经访问到第四个点了,而1这个点没有被覆盖到,和1有联系的最大的点有2,2<4,说明2已经被访问过了,说明了1和2之间没有放置服务器,而后面的点又影响不到1这个点的状态了。所以将该枝剪掉

简化一下,将和点相连的点列成一个数组,然后将该数组按从大到小的顺序排序,再判断该数组中的最大的点(数组中的第一个)和当前访问点的大小,如果该数组中最大的那个点小于当前访问点且该点没被覆盖,则剪掉,因为后面已经没有点能和该点相连接了

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

#define maxn 40
int N,M,Min,rec[maxn];
int g[maxn][maxn],son[maxn];

int cmp(const int &a,const int &b) {
	return	a>b;
}

void DFS(int cur,int n, int sum) {

	if(sum >= Min) //剪枝1,如果要覆盖的次数大于最小值的话就剪断
		return ;
	if(n == N)//如果符合上面的要求的话,就表名sum必小于Min
		Min = sum;
	for(int i = 1; i < cur; i++)
		if(!rec[i] && g[i][0] < cur)//剪枝3,
			return ;
	DFS(cur+1,n,sum);//递归下一个点
	int mark = 0;//记录有几个需要存储的,并判断是否剪枝
	int vis[maxn];//暂时存储的作用

	for(int i = 0; i < son[cur]; i++){//判断和该节点相连接的节点是否有覆盖,如果都已经覆盖了,就剪枝,如果没有覆盖的话,就记录,并让其覆盖
		if(rec[g[cur][i]] == 0) {
			rec[g[cur][i]] = 1;
			vis[mark++] = g[cur][i];
		}	
	}

	if(!mark)//判断是否剪枝
		return ;

	DFS(cur+1,n+mark,sum+1);//如果当前节点符合,就递归,覆盖次数加1,sum+1,覆盖点加mark个,n+mark

	for(int i = 0; i < mark; i++)//回溯,将那些被覆盖的点还原
		rec[vis[i]] =  0;	
}

int main() {
	int a, b;
	while(scanf("%d%d",&N,&M) && N+M) {
		memset(son,0,sizeof(son));
		memset(rec,0,sizeof(rec));
		memset(g,0,sizeof(g));

		for(int i = 0; i < M; i++) {
			scanf("%d %d",&a,&b);
			g[a][son[a]++] = b;//每一个点列一个数组,后面跟的是和他相连接的点,son记录有几个相连节点有几个
			g[b][son[b]++] = a;
		}

		Min = N + 1;
		for(int i = 1; i <= N; i++) {
			g[i][son[i]++] = i;
			sort(g[i],g[i]+son[i],cmp);//将节点从小到大排序,后面好判断是否需要剪枝
		}
		DFS(1,0,0);	
		printf("%d\n",Min);
	}
	return 0;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值