上次给大家讲了一篇关于无脑枚举的编(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;jif(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了一道动态规划题。