UVa 10160 Servicing stations解题报告

来源:互联网 发布:淘宝网耐克运动鞋 编辑:程序博客网 时间:2022/10/02 15:00

UVa 10160 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.

    一家提供个人电脑的公司在N个镇出售电脑(3<= N<=35)。城镇被记为1,2,...,N,这些城镇之间有M条路相连。该公司决定在几个城镇建立服务站,使得对于任何城镇X,都会有在X或在某些与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.

    输入的数据由多组关于小镇的描述组成(不过总数不会超过10组)。每组数据首先是城镇的数量N和道路的数量M。N和M之间用一个空格隔开。接下来的M行每行给出一对城镇,表示这两个城镇之间有路,每两个城镇之间用一个空格隔开。当N=0且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

    这是来源于编程挑战上的一道搜索题,也是一道相对来讲比较好写的深搜。基础的思路比较好想,只需要从第一个点开始枚举,直到所有的点都被覆盖,寻找最优解。但是如果这样裸搜的话,35的范围是一定会炸的,所以要考虑一些剪枝。

    首先可以发现,如果在某一个点建立一个服务站后,所能覆盖的点数量并没有增加,那我们还不如不放。

    然后如果一条路走到一半,就发现此时设置的服务站数已经大于或是等于当前的最优解,那这条路就可以剪了。

    接下来进一步思考还可以发现,如果在初始化的时候,将每个点所能覆盖的点按照编号从小到大排序,那么在接下来深搜的时候,如果搜到当前点时,编号小于当前点 并且没有被覆盖的点 所能通向的点中 最大编号的点 也小于当前点的编号,那么就可以放弃这条路了,因为继续向下搜也不可能覆盖这个点了。实践证明,做到这三个剪枝就可以A了,不过还有几个优化可以使用(A了以后想出来的,懒得去再实现了0.0....):

    1.如果一个点a所能通向的点只有一个点b,那么b点一定要建一个服务站。如果一个点没有能通向的点,则该点处一定要建一个服务站。

    2.可以在每次建站完后动态修改每个点此时能通向还未被覆盖的点的数量,然后优先考虑能通向还未被覆盖的点多的点,这样根据上面的剪枝可以更快找到最优解。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 36using namespace std;int n,m,minn;int a[N][N],f[N],c[N];bool cmp(const int &x,const int &y){return x>y;}void put(int x,int k,int s){if (k==n && s<minn) minn=s;if (s>=minn) return;for (int i=1; i<=x; i++)if (!f[i] && x>a[i][1]) return;put(x+1,k,s);int v=0,b[N];for (int i=1; i<=c[x]; i++)  if (!f[a[x][i]])  {f[a[x][i]]=true;b[++v]=a[x][i];  }if (!v) return;else s++,k+=v;put(x+1,k,s);for (int i=1; i<=v; i++) f[b[i]]=false;}int main(){while (scanf("%d%d",&n,&m)==2){if (!n && !m) break;minn=n+1;memset(a,0,sizeof(a));memset(c,0,sizeof(c));memset(f,false,sizeof(f));for (int i=1; i<=m; i++){int x,y;scanf("%d%d",&x,&y);a[x][++c[x]]=y;a[y][++c[y]]=x;}for (int i=1; i<=n; i++){a[i][++c[i]]=i;sort(a[i]+1,a[i]+c[i]+1,cmp);}put(1,0,0);printf("%d\n",minn);}return 0;}


0 0
原创粉丝点击