复杂状态的动态规划

来源:互联网 发布:激萌软件下载 编辑:程序博客网 时间:2024/05/16 17:00


最优配对问题:


空间里有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);}}







end~
0 0
原创粉丝点击