Servicing stations +uva+回溯+剪枝

来源:互联网 发布:淘宝客定向计划是什么 编辑:程序博客网 时间:2024/04/23 16:26

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

解决方案:本题必须剪枝,如何剪枝,有几个地方可剪。

1)若搜索过程中,还未结束得到要放station数比之前得到的结果还多,那必须剪。

2)若搜索过程中,已过的点中,有没有station或相邻的station,而且未过的点也没有与其相邻的点,则该点到了结束都不会有station service直接或间接的提供,必剪

3)若搜索过程中,要放置station的点,放station和不放station都一个样,这个也可剪。

经过这些剪枝之后,4s多通过,不知还有没有其他剪枝。

代码:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int N,M,Min,statNum,act;int Map[50][50];int city_state[50];int dfs(int cur){     if(statNum>Min)        return 0;///如果未搜完是,要建的station的数目比之前搜到的多,则剪枝。     if(cur>N){        if(act==N){           if(statNum<Min)                Min=statNum;        }     }     else {          for(int i=1;i<=cur-1;i++)            if(city_state[i]==0){                    int j;                for(j=cur;j<=N;j++){                    if(Map[i][j]){                        break;                    }                }                if(j>N) return 0;            }///若前以搜过的点中,有的点现在和以后都无法让其activity,剪枝     int old_act=act;     if(city_state[cur]==0){        act++;     }///若之前没有使其activity,act个数要加1     city_state[cur]++;///city_state[cur]要加1     statNum++;///放置一个source     for(int i=1;i<=N;i++){        if(Map[cur][i]){            if(city_state[i]==0){                act++;            }            city_state[i]++;        }     }///与cur相邻的也要加1     if(act>old_act){        dfs(cur+1);     }///若该cur加source上去,会有所变化,就进入下一个cur的搜索,否则,该cur不加source,这也是一个剪枝      for(int i=1;i<=N;i++){        if(Map[cur][i]){            city_state[i]--;            if(city_state[i]==0){                act--;            }        }     }///若cur没有了source,其相邻的city_state都要减1,如果有的从activity变为了no activity则act减1     city_state[cur]--;     statNum--;     if(city_state[cur]==0){        act--;     }///以上是不放source的情况     dfs(cur+1);     }     return 0;}int main(){    while(~scanf("%d%d",&N,&M)&&(N+M)){            memset(city_state,0,sizeof(city_state));            memset(Map,0,sizeof(Map));        for(int i=0;i<M;i++){            int st,en;            scanf("%d%d",&st,&en);            Map[st][en]=1;            Map[en][st]=1;        }        statNum=0;        Min=100;        act=0;        dfs(1);        cout<<Min<<endl;    }    return 0;}

0 0