uva 10160 Servicing Stations

题目地址:

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1101

题目描述:

Problem D: 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


题意:最小支配集问题,或者说发电站,在一个城市放发电站,这个城市和直接邻接城市都会有电。问使所有城市都有电的最小放置发电站的个数。

题解:一、DFS+剪枝 二、DFS+状态压缩+剪枝

一:

首先想到DFS,城市就是两种状态放发电站 还是  不放发电站 如此深搜下去可以得到最小的放置发电站个数,但35的数据规模是不允许不剪枝的。

配合上面的DFS剪枝,目前想到的就三个:

1、放置发电站后,其产生的作用为0,即放置这个发电站后,有电的城市还是有电,没电的城市还是没电,也就是说放置发                                                                                  电站后,状态从无电变为有电的城市为0。(注意,有电的城市是可以重复有电的,即被多家不同的邻接发电站供电,放置        发电站的城市也可以是有电的,只要城市本身没有发电站就行)这样的情况剪掉不再深搜下去。

2、记录每一种成功的能覆盖全城市的发电站放置个数(但不一定是最优的),再以后的其他情况放置的搜索过程中,若当前        的发电站放置个数已经大于记录里保存的成功覆盖城市的发电站个数,直接将这种搜索情况剪掉(因为再搜下去,只会        比记录里的大根本不可能是最优解)。

3、在深搜到某一点时,他之前存在着没有电的点,而这个某一点之后的其他点即我们后面要搜到的点也没有与前面的这个无 电的点直接邻接连通,那么意味着这趟搜索直到结束,这个无电的点也永远无电(不能再在这个城市放发电站,因为搜       索过程已经到后面的点;也不能通过后续的点放发电站对他供电因为根本不直接连通邻接),显然不能满足覆盖全城市有      电的条件,剪掉这种情况。

代码:

/*
three prunes for this DFS(maybe not for only 3)
1.place this station but no any different from  before,that is to say  the act is not increased
2.save the succeed MinSta,if the other DFSs the StaNum>MinSta then we need not DFS this case
3.if we DFS the cur  but the 1~cur have the unactivity node and cur ~ n have no cnnect to this unactivity node,so this node would be unactivity forever so we prune it
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <iostream>
#include <algorithm>

using namespace std;

int N=0,M=0;//undirected graph  N vertex  M edges
int StaNum=0;//number of station
int MinSta=0;// min number of station
bool Graph[35+5][35+5]={false};//begin with 1
int StaTo[35+5]={0};//the status of the towns,begin with 1,ths stato[i]++ it's value can be cover and repeat
int act=0;//act is activity number of the towns
int PointDegree[35+5]={0};//save the point's degree

/*DFS the graph*/
int DFS(int cur)
{
	//2 prune
	if(StaNum>MinSta)
	{
		return(0);
	}
	if(cur>N)
	{
		if(act==N)
		{
			if(StaNum<MinSta)
			{
				MinSta=StaNum;
			}
		}
	}
	else
	{
		//3 prune
		int i=0,j=0;
		for(i=1;i<=cur-1;i++)
		{
			if(StaTo[i]==0)
			{
				for(j=cur;j<=N;j++)
				{
					if(Graph[i][j])
					{
						break;
					}
				}
				if(j>N)
				{
					return(0);//the point i would be unactivity forever
				}
			}
		}
		int oldact=act;
		//place the source
		if(StaTo[cur]==0)
		act++;
		StaTo[cur]++;
		StaNum++;
		//activate the neighbour
		for(i=1;i<=N;i++)
		{
			if(Graph[cur][i])
			{
				if(StaTo[i]==0)
				{
					act++;
				}
				StaTo[i]++;
			}
		}
		if(act>oldact)//1 prune
		DFS(cur+1);
		for(i=1;i<=N;i++)
		{
			if(Graph[cur][i])
			{
				StaTo[i]--;
				if(StaTo[i]==0)
				{
					act--;
				}
			}
		}
		StaNum--;
		StaTo[cur]--;
		if(StaTo[cur]==0)
		{
			act--;
		}
		//don't place the source
		DFS(cur+1);
	}
	return(0);
}

/*for test*/
int test()
{
	return(0);
}

/*main process*/
int MainProc()
{
	while(scanf("%d%d",&N,&M)!=EOF&&(N+M)>0)
	{
		//init
		memset(Graph,false,sizeof(Graph));
		memset(StaTo,0,sizeof(StaTo));
		memset(PointDegree,0,sizeof(PointDegree));
		MinSta=100;
		StaNum=0;
		act=0;
		int toStart=0,toEnd=0;
		int i=0;
		int MaxDegree=0;
		int MaxIndex=0;
		for(i=1;i<=M;i++)
		{
			scanf("%d%d",&toStart,&toEnd);
			Graph[toStart][toEnd]=true;
			Graph[toEnd][toStart]=true;
		}
		DFS(1);
		printf("%d\n",MinSta );
	}
	return(0);
}

int main(int argc, char const *argv[])
{
	/* code */
	MainProc();
	return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值