1. 程式人生 > >uva140_dfs(回溯)最優性剪枝

uva140_dfs(回溯)最優性剪枝

///////////////////////////////////////////////////////////////////////////////////////////////////////
作者:tt2767
宣告:本文遵循以下協議自由轉載-非商用-非衍生-保持署名|Creative Commons BY-NC-ND 3.0
檢視本文更新與討論請點選:http://blog.csdn.net/tt2767
連結被刪請百度: CSDN tt2767
///////////////////////////////////////////////////////////////////////////////////////////////////////

題解:
1.原書中已經說明,如果兩個節點的頻寬 >= 最小頻寬,無論如何也不可能比原解更優,應該剪掉。

2.注意此題讀入的時候一定要按 字典序 儲存,這樣計算出的最小值才是符合要求的

3.注意strtok的用法


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath> ////////////////////// #include<iostream> #include<algorithm> #include<string> #include <iterator> #include<sstream> #include<functional> #include<numeric> /////////////////////// #include<vector> #include<map> #include <stack> #include<queue> #include<set>
#include <bitset> #include <list> using namespace std; #define lch(x) ((x) << 1) #define rch(x) ((x)<<1|1) #define dad(x) ((x)>>1) #define lowbit(x) ((x)&(-x)) typedef long long int LL; const int INF = ~0U>>1; const double eps = 1e-6; const long double PI = acos
(0.0) * 2.0; const int N = 10+200; map<char,int> id; int mi ,n; char in[N]; int v[N],ans[N],tmp[N]; bool vis[N],G[N][N]; bool read(); void dfs(int cur , int x); int ID(char x){return id[x];} int main() { //ios::sync_with_stdio(false); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); //freopen("out3.txt", "w", stdout); #endif while(read()) { mi = n; //頻寬最大為n dfs(0,0); //dfs(當前位置,上一次算的頻寬) for(int i = 0 ; i < n ; i++) printf("%c ",v[ ans[i] ]+'A'); printf("-> %d\n",mi); } return 0; } bool read() { gets(in); if(in[0]=='#') return 0; char * p,*s=in; memset(vis,0,sizeof(vis)); int l = strlen(in); for(int i = 0 ; i< l ; i++) if(isalpha(in[i])) vis[in[i]-'A']=1; //字典序查詢點 n = 0; //按字典序把點對映,並收集起來 for(int i = 0 ; i < 27 ; i++) if(vis[i]) v[ id[i+'A']=n++ ] = i; memset(G,0,sizeof(G)); while(p = strtok(s,";"))//分割字串 { for(int i = 2 ; p[i]!='\0' ; i++) //轉化成鄰接矩陣儲存,方便查詢 G[ ID(p[0])][ ID(p[i]) ] = G[ ID(p[i])][ ID(p[0])] = 1; s = NULL; } memset(vis,0,sizeof(vis)); return 1; } void dfs(int cur , int x) { if(cur == n)//能執行到這一步的值必定比前一個小 { //更新它 mi = x; memcpy(ans,tmp,sizeof(tmp)); return ; } for(int i = 0 ; i < n ; i++)//回溯生成排列 { if(!vis[i]) { vis[i] = 1; tmp[cur] = i; int dk = 0; for(int j = 0 ; j < cur ; j++) { if(G[ i ][ tmp[j] ]) { dk = cur - j; break; } } dk = max(x,dk); if(dk < mi) dfs(cur+1,dk); //如果某個節點的頻寬比當前最小頻寬大,剪掉它 vis[i] = 0; } } }