NP完全性和近似算法

NP完全性

P类问题:P类问题就是在多项式时间内可以解决的问题。
NP类问题:NP类问题是指那些在多项式时间内可以被证明的问题。
NP完全性:如果一个问题L满足:1. L在NP中;2. 对于NP中的任意问题L’,L’可以多项式时间归约到L;则说L是NP完全(NP-Complete)的。

典型的NP完全性问题

电路满足问题:给定一个只由AND,OR和NOT组成的n输入-单输出布尔组合电路,是否存在一个输入指派,使得电路输出为1?一个布尔组合电路不能包含有向环。

最优顶点覆盖问题:在一个给定的图中,找到具有最小规模的顶点覆盖(所有的边至少有一点是和集合中的顶点相连的)。

子集和问题:给定一个数组,判断是否存在一个子集合,使得其中的数加起来恰好为目标值t。

固定参数算法

如果我们知道一个问题是NP完全性的,那么我们就不必去寻找多项式时间的解法,转而寻找一种其他的解决方案。

固定参数是对原问题添加了一个参数k,并且使得算法的复杂度的指数部分只和这个参数k相关,而其他部分为多项式,使得在问题规模较小的时候,可以得到解决。

在顶点覆盖问题中,固定参数算法增加了一个参数,能否在k个顶点内覆盖所有的边。这里,有一种算法的复杂度为,这样,在k较小时,问题可以得到解决。

近似算法

最优解问题,如果对规模为n的任意输入,近似算法产生的近似解的代价与最优解的代码只差一个一个因子,这称该算法为近似算法。

对于顶点覆盖问题,有这样一个算法:

C=空
E = 图中所有的边
while(E不为空)
    选择E中任意一边
    将和边相连的两个顶点加入到C,去重
    将和两个顶点的相连的边从E中移除
return C

这个算法产生的解法产生的顶点最多为最优解的两倍(具体的说明见算法导论相关章节)。

近似模式

近似模式和近似算法不同的是,近似模式有一个参数,可以通过调节这个参数调节和最优解的差距,当然,越精确,复杂度就越高。下面是一个子集和问题的精确解法,当不能等于t时,会输出最接近的那个数。

#include
using namespace std;

int subsetSum(vector &arr, int target){
    vector v;
    v.push_back(0); // 一个都不选
    for(int i=0;i target){ //去掉大于target的部分
            v.pop_back();
        }
    }
    return v.back();
}

int main(int argc, char const *argv[])
{
    int n,target;
    cin>>n>>target;
    vector arr(n,0);
    int sum = 0;
    for(int i=0;i

这里近似的一个参数是替代值,如果把相近的值都用一个值来替代,这样可以减少数组中元素,提高速度。

总结

对于NP完全性问题,在问题规模较小时,我们可以考虑指数时间的精确解,问题规模较大时,我们可以使用近似算法,使用一种启发性的算法来得到近似解。启发式的策略有点像贪婪算法,想到某种策略并不难,难的是说明这种算法和最优解的差距。至于近似模式,感觉并不是所有的问题都能有这样一种方法。

感觉比较难,但还是做个笔记吧,还是开了一点眼界。

你可能感兴趣的:(NP完全性和近似算法)