回溯法复习(二)

UVa140

这是一道典型的回溯法题目,第一次做的时候并没有做出来,在参考了网上的一些AC代码后经过修改,终于AC成功了。

下面先附上代码:

#include 
#include 
#include 
#include 
using namespace std;
const int maxn = 10;
char letter[maxn]; 
int id[256];
char str[100];
int p[maxn];
int pos[maxn];
int vis[maxn];
int n;
int bestP[maxn];
int bindwidth;
int bestW;
int g[maxn][maxn];
void dfs(int cur)
{
	if(cur == n)
	{
		bindwidth = 0;
		for(int i = 0;i=bestW)
					{
						ok = 0;
						break;
					}
				}
				for(int j = 0;j=bestW)	ok = 0;
				if(ok)
				{
					vis[i]=1;
					dfs(cur+1);
					vis[i]=0;
				}	
			}
	}
}
int main()
{
	while(scanf("%s",str)==1)
	{
		if(str[0]=='#') break;
		n = 0;
		memset(g,0,sizeof(g));
		bindwidth = 0;
		bestW = 0x7fffffff;
		memset(vis,0,sizeof(vis));
		for(char c = 'A';c<='Z';c++)
			if(strchr(str,c)!=NULL)
			{
				letter[n]=c;
				id[c]=n++;
			}
		int len = strlen(str);
		int t;
		for(int i = 0;i %d\n",bestW);
	}
	return 0;	
} 
首先这个题目的注意要点有以下几个:

1)双向映射的程序写法,使用strchr函数进行letter和id数组的赋值,而且进行了潜在的排序操作。

2)图的表示,这里我用了邻接矩阵表示,便于进行剪枝的有关计算,这里在dfs中进行了两个剪枝的操作(根据书上的提示):

a)当当前访问的节点位置cur与前面的位置,之间的带宽大于等于当前最大带宽,剪枝;

b)当与当前访问节点相邻的不确定的节点数量大于等于当前带宽,剪枝。

网上的一些方法使用next_permutation()函数,在代码规模上较小,但是在剪枝情况上不如直接通过dfs回溯方法操作的好。当然这对算法的正确性并没有影响,但是作为训练,我依然使用了这种dfs的方法。

UVa1354

#include 
#include 
#include 
#include 
using namespace std;
const int n = 6;
const int maxn = 1< tree[maxn];
int vis[maxn];
int bitcount(int x) {  
    if (x == 0) return 0;  
    return bitcount(x / 2) + (x & 1);  
}  
void dfs(int u)
{
	if(vis[u]) return;
	vis[u]=1;
	if(bitcount(u)==1)
	{
		tree[u].push_back(Node(0,0));
		return;
	}
	for (int l = (u - 1)&u; l > 0; l = (l - 1)&u) //枚举二叉树的子树
	{
		int r = l^u;
		dfs(l); dfs(r);  
        for (int i = 0; i < tree[l].size(); i++) {  
            for (int j = 0; j < tree[r].size(); j++) {  
                double ll = max(sumw[r] / (sumw[l] + sumw[r]) + tree[l][i].l, -sumw[l] / (sumw[l] + sumw[r]) + tree[r][j].l);
				double rr = max(sumw[l] / (sumw[l] + sumw[r]) + tree[r][j].r, -sumw[r] / (sumw[l] + sumw[r]) + tree[l][i].r);
                tree[u].push_back(Node(ll, rr)); 
            }  
        }
	}
	
}
double solve()
{
	int root = (1<
这道题的注意点有以下几个:

1)二进制方法枚举子集

2)对树的节点构建一个表,每一行对应一个节点集合,每个元素对应每种情况下的左右节点。

3)二进制枚举二叉树的子树

以上两个题目的解答方法都借鉴了一些网上的解法,但在很多细节处与网上的代码有所不同。

谢谢大家的阅读。


你可能感兴趣的:(算法)