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.
Sample Input
Accepted 660ms (resourse:virtual judge)
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
SampleOutput
2
- 题目大意:给定n个城市,m条无向边分别连接两个城市。若城市x建造了发电厂,则与x相连的城市都有电供应。求使所有城市都有电供应所需的最小发电厂数。
- 思路:回溯法+剪枝
- 可行性剪枝1:若当前已有n个城市有了电,即所有城市都通了电,则记录当前最小值。
- 可行性剪枝2:若当前搜索到的城市n前面1~n-1编号的城市中有没有通电的,则永远也无法输送电力给那个城市,无解。
- 剪枝2实现方法:用邻接数组存储每个点相邻的点,将每个邻接数组的点以其编号为关键字降序排序,dfs判断时若前面1~n-1个点中有没有电的,并且它的最大编号儿子的编号小于当前城市(即搜索序更小,已经搜索过却无电),则剪枝。
- 最优化剪枝:若当前要用的最小发电厂数已经超过了当前求得最有解,则剪枝。
Accepted 660ms (resourse:virtual judge)
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int g[40][40],son[40],n,m,ans; bool elt[40]; bool cmp(const int &a,const int &b) { return a>b; } void Init() { ans=n+1; memset(g,0,sizeof(g)); memset(elt,0,sizeof(elt)); memset(son,0,sizeof(son)); for(int i=0; i<m; i++) { int u,v; scanf("%d%d",&u,&v); g[u][son[u]++]=v; g[v][son[v]++]=u; } for(int i=1; i<=n; i++) { g[i][son[i]++]=i; sort(g[i],g[i]+son[i],cmp); } } void dfs(int cur,int elcity,int sum) { if(sum>=ans)return;//tree cut 1; if(elcity==n) ans=sum; for(int i=1; i<cur; i++) //tree cut 2; if((!elt[i])&&(g[i][0]<cur)) return; dfs(cur+1,elcity,sum); int k=0,vis[40]; for(int i=0; i<son[cur]; i++) if(!elt[g[cur][i]]) { elt[g[cur][i]]=1; vis[k++]=g[cur][i]; } if(!k)return;//tree cut 3; dfs(cur+1,elcity+k,sum+1); for(int i=0; i<k; i++) elt[vis[i]]=0; } int main() { while(scanf("%d%d",&n,&m),n+m) { Init(); dfs(1,0,0); printf("%d ",ans); } return 0; }