uva140_dfs(回溯)最優性剪枝
阿新 • • 發佈:2019-01-31
///////////////////////////////////////////////////////////////////////////////////////////////////////
作者: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;
}
}
}