上次给大家讲了一篇关于无脑枚举的编(O)程(J)题(shui)目(ti)。大家是不是觉得枚举既简单又简(bao)单(li)呢?可是除了水题,没有一个题目会安心让你枚举的,到时候就是WA,RE,TL,OL的餐具,比如下面这题:
通讯线路(haywire.cpp)
FJ的N(4 <= N <= 12 , N 为偶数)头牛建立起原始的通讯系统,在每一对好友之间建起通讯线路。
每头牛都恰好有3 个好友。
所有的奶牛站成一行。占据数轴上1. .N的坐标。如果站在坐标为4 和7 的牛是好友,则需要建一条长为3 的线路。
每一对好友都需要建立单独的线路。
给出每头牛的好友信息。求怎样安排牛的位置,使得通讯线路的总长度最短。
INPUT FORMAT:
第1 行:1 个整数N,表示奶牛的数量。奶牛编号为1. .N
接下来N行,每行3 个整数,表示第i头牛的好友编号。好友关系是相互的。
SAMPLE INPUT (file haywire.in ):
6
6 2 5
1 3 4
4 2 6
5 3 2
4 6 1
1 5 3
OUTPUT FORMAT:
第1 行:1 个整数,表示最短的通讯线路总长度
SAMPLE OUTPUT (file haywire.out ):
17
OUTPUT DETAILS:
A best ordering of the cows is 6 , 5 , 1 , 4 , 2 , 3 , which requires only 17
units of hay.
这题题干一看就是要全排列的节奏啊,毕竟搜索还不如枚举,动态规划也不怎么明了,不如就无脑的暴力搜索吧!
于是乎:
void search (int e ){
for (int i =1;i<=m;i++){
c [e ]=i;
vis [i ]=1;
search (e +1 );
c [e ]=0;
vis [i ]=0;
}
}
就这一个递归就能模拟全排列了,但超时不可避免的出现了。
所以,在数日寝食难安后,我接受了最优化剪枝的方法:
就是枚举,不过每枚举一个位置的牛都要预估一个值,即为还没处理的朋友的个数。
优化后是这样的:
void search(int e,int p,int d,int f){
if (p+d>=sum ){
return ;
}
if (e>m)
{
if (d+p<sum )
sum =d+p;
return ;
}
for (int i=1 ;i<=m;i++){
if (vis[i]==0 ){
int F=3 ,P=0 ,D=0 ;
for (int j=1 ;j<e;j++)
{
if (a[c[j]][i]==1 ){
F-=2 ;
P-=e-j;
D+=e-j;
}
}
c[e]=i;
vis[i]=1 ;
search(e+1 ,p+P+F+f,D+d,f+F);
c[e]=0 ;
vis[i]=0 ;
}
}
}
注意第二行的if(p+d>=sum)的等于一定要加,可以快接近一半的速度。
OK,我就这样用枚举AC了一道动态规划题。