uva 10160 Servicing Stations(DFS+剪枝)

Servicing stations

A company offers personal computers for sale in N towns (3 <= N <= 35). The towns are denoted by 1, 2, …, N. There are direct routes connecting M pairs from among these towns. The company decides to build servicing stations in several towns, so that for any town X, there would be a station located either in X or in some immediately neighbouring town of X.

Write a program for finding out the minumum number of stations, which the company has to build, so that the above condition holds.

Input
The input consists of more than one description of town (but totally, less than ten descriptions). Every description starts with number N of towns and number M of pairs of towns directly connected each other. The integers N and M are separated by a space. Every one of the next M rows contains a pair of connected towns, one pair per row. The pair consists of two integers for town’s numbers, separated by a space. The input ends with N = 0 and M = 0.
Output
For every town in the input write a line containing the obtained minimum.
An example:
Input:

8 12
1 2
1 6
1 8
2 3
2 6
3 4
3 5
4 5
4 7
5 6
6 7
6 8
0 0

Output:

2

题目大意:给出n个点和m个关系,可以在任何一个点放服务站,如果这个点放了服务站,与它相连得点均可以被服务到,问最少放多少个服务站可以使得所有所有点均可以被服务到。

解题思路:思路很简单,用DFS收索,关键就在与剪枝,我的主要优化在于两个地方。

首先按点得序号开始DFS, cur 表示当前访问得点。

<1>对于每个点,无非就是放与不放(注意这里不能单纯根据这个点有没有被覆盖到去判断该不该放服务站)

<2>第一个剪枝,如果这个点增加服务站之后,被覆盖得点数没有增加,就可以确定当前点是不放(与放得情况相同干嘛要多加一个点)

<3>第二个剪枝,当放得服务站个数大于前面计算的最小值时,剪掉这条路。

<4>第三个剪枝,当出现前面有的点无法被覆盖得时候,可以终止这条路得收索。

这里问解释一下第三个剪枝得情况,比如当前已经访问到第5个点,而1 这点任然没有被覆盖到,而与1 有联系得点2,2 < 5, 说明2 已经被访问过了,说明1 和 2 都没有放服务站,而后面n个点得放与不放都影响不到1 得覆盖状态,所以这条路是无法被满足的。

//解题方法: 回溯加剪支 
int g[40][40];
int rec[40];
int son[40];
int Min=1000;
int cmp(const int a,const int b){
	return a>b;//从小到大 
}
int n,m;
void dfs(int cur,int cnt,int sum){
	if(sum>=Min)
	return ;
	if(cnt==n){
		Min = sum;
		return ;
	}
	for(int i=1;i<cur;i++){
		if(!rec[i]&&g[i][0]<cur){
			return ;
		}
	}
	dfs(cur+1,cnt,sum);//不放服务器(不进行覆盖)
	int k=0,vis[1000];
	for(int i=0;i<son[cur];i++){
		if(!rec[g[cur][i]]){
			vis[k++] = g[cur][i];
			rec[g[cur][i]]=1;
		}
	}
	if(!k)	return ;
	dfs(cur+1,cnt+k,sum+1);//放置一台服务器
	//回溯
	for(int i=0;i<k;i++){
		rec[vis[i]]=0;
	} 
}
int main()
{  
   while(cin>>n>>m&&(n||m)){
   	FILL(g,0);
   	FILL(rec,0);
   	FILL(son,0);
   	Min=1000;
   	for(int i=0;i<m;i++){
   		int a,b;cin>>a>>b;
   		g[a][son[a]++] = b;
   		g[b][son[b]++] = a;
	   }
	   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;	
}

猜你喜欢

转载自blog.csdn.net/Csdn_jey/article/details/90484457
今日推荐