zoukankan      html  css  js  c++  java
  • 复杂状态的动态规划



    最优配对问题:


    空间里有n个点P0,P1,…,Pn-1,你的任务是把它们配成n/2对(n是偶数),使得每个点恰好在一个点对中。
    所有点对中两点的距离之和应尽量小。 




    dp方程:


    d[i][S] 点0~i 的最优匹配,S为状态集合。
    d[i][S] = min(d[i][j],dist(i,j)+d[i-1][S-{i}-{j}]); 
    集合 S 和 j 是否有交集 (S&(1<<j)) ; 
    除去 i j 的集合怎么表示呢? d[i-1][S^(1<<i)^(1<<j)];

    for(int i=0; i<n; i++){
        for(int S=0; S<(1<<n); S++){
            d[i][S] = INF;
            for(int j=0; j<i; j++)
                d[i][S] = min(d[i][S],dist[i][j]+d[i-1][S^(1<<i)^(1<<j)]);
        }
    }



    -----------------------------------------------------------------------------------------------------------------------


    i 一定是S中最大的元素,那么dp就可以减少一维
    d(S) = min(|PiPj| + d(S-{i}-{j})) | i = max(S);

    for(int S=0; S<(1<<n); S++){
        int i,j;
        d[S] = INF;
        for(int i=0; i<n; i++)
            if(S&(1<<i)) break;
        for(int j=i+1; j<n; j++)
            if(S&(1<<j)) d[S] = min(d[S],dist[i][j]+d[S^(1<<i)^(1<<j)]);
    }




    注意,在上述的程序中求出的i是S中的最小元素,而不是最大元素,但这并不影响答案
    另外, j的枚举只需从i+1开始-- 既然i是S中的最小元素,则说明其他元素都比i大
    S的枚举顺序:如果S’ 是S的真子集,则一定有S‘<S,因此若以S递增的顺序计算,需要用到某个d值时,它一定已经计算出来了


    *************************************************************************************************************************


    货郎担问题(TSP) N<=15 城市编号0~n-1


    有n个城市,用1,2,…,n表示,城i,j之间的距离为L[i][j],有一个货郎从一个城市出发到其他城市一次且仅一次,最后回到起点的路线,
    怎样选择行走路线使总路程最短?


    是NPC难题,,规模小可以用dp求解
    首先可以注意到可以直接规定起点和终点为城市0,然后设d(i,S)表示当前在城市i,还需访问集合S中的城市各一次后回到城市0的最短长度
    状态转移: d(i,S) = min{ d(j,S-{j}) + dist(i,j)|j∈S }


    边界为: d{i,{}} = dist(0,i); 
    最终答案: d(0,{1,2,3,....,n-1}); 
    时间复杂度为O(n^2*2^n);




    **************************************************************************************************************************


    图的色数:


    图论有一个经典问题是这样的:给一个无向图G,把图中的结点染成尽量少的颜色,是的相邻结点颜色不同


    设d(S)表示把结点集S染色,所需要颜色数的最小值,则d(S) = d(S-S’)+1, 其中S’是S的子集,并且内部没有边(即不存在S‘内的两个结点u和v使得u和v相邻)
    换句话说,S’是一个"可以染成同一颜色" 的结点集


    首先通过预处理保存每个结点集是否可以染成同一颜色(即“内部没有边”) , 则算法的主要时间取决于“高效的枚举一个集合S的所有子集

    d[0] = 0;
    for(int S=1; S<(1<<n); S++){
        d[S] = INF;
        for(int s0=S; s0; s0=(s0-1)&S){
            if(no_edges_inside[s0])
                d[S] = min(d[S],d[S-s0]+1);
        }
    }
  • 相关阅读:
    如何雇人的十五条建议
    如何通过预加载器提升网页加载速度
    提升代码内外部质量的22条经验
    敏捷团队的组织与管理--- MPD软件工作坊培训感想(下)
    敏捷开发的道与术---MPD软件工作坊培训感想(上)
    分享自制的C#和VB Code互转工具
    基于 WPF 平台的 ActiveReports Viewer控件
    在ASP.NET MVC 中使用ActiveReports报表控件
    根据数据源字段动态设置报表中的列数量以及列宽度
    在ActiveReports页面报表中显示Google地图
  • 原文地址:https://www.cnblogs.com/yxg123123/p/6827741.html
Copyright © 2011-2022 走看看