最优化剪枝——不无脑的枚举

上次给大家讲了一篇关于无脑枚举的编(O)程(J)题(shui)目(ti)。大家是不是觉得枚举既简单又简(bao)单(li)呢?可是除了水题,没有一个题目会安心让你枚举的,到时候就是WA,RE,TL,OL的餐具,比如下面这题:
通讯线路(haywire.cpp)

FJ的N(4 <= N <= 12, N 为偶数)头牛建立起原始的通讯系统,在每一对好友之间建起通讯线路。
每头牛都恰好有3个好友。
所有的奶牛站成一行。占据数轴上1..N的坐标。如果站在坐标为47的牛是好友,则需要建一条长为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了一道动态规划题。

你可能感兴趣的:(水题)