题目:https://vjudge.net/problem/UVA-140

解题思路:


1.全排列:使用库函数next_permutation(a,a+n)

2.最优性剪枝:如果目前已经找到的最小带宽是k,若在新的一组排列中,发现已经有两个结点的距离大于或等于k,应强制把它“剪”掉,即剪枝。

3.全排列时肯定要对输入中出现的字母所对应的int数组做全排列,所以要对出现的字母做标记!

(1)首先A~Z每个字母在读入的字符数组s[]中遍历,查找是否出现过,num初始为0

         若出现,letter[num]=ch;   id[ch]=num++;

         则可对s[]中出现的所有字母(不重复)按照字典序从小到大编号,即id

  (2)vector<int> u,v;

            遍历s[],将  :前面的字母对应的id加入u中, :后面的字母对应的id加入v中,且这两个操作同时进行

  (3)p[]输出初始化为p[i]=i; //p[]记录每次全排列后对应的id序列

            每次pos[p[i]]=i;  //pos[]记录id(id=p[i])在全排列后的序列中的位置

           (举例:p[]第一全排列即初始化后为:{0,1,2,3,4,5,6}

                             pos[p[5]]=pos[5]=5; pos[p[6]]=pos[6]=6; //id=5在位置5,di=6在位置6

                          p[]第二次全排列后为:{0,1,2,3,4,6,5}

                             pos[p[5]]=pos[6]=5;  pos[p[6]]=pos[5]=6;//id=6在位置5,id=5在位置6

             因为id对应着字母,所以可以知道两个字母之间的带宽,即abs(pos[u[i]]-pos[v[i]])

              )

           不断更新最优的带宽对应的全排列id序列,用memcpy(ansp,p,sizeof(p))比数组一个一个赋值要快

            执行next_permutation(p,p+num);

     把样例带进入执行一遍就懂了!

 

ac代码:


#include <iostream>
#include <cmath>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <sstream>
#define maxn 10
#define inf 0x3fffffff
using namespace std;
typedef long long ll;
int id[100];//字母对应的编号,(int)'Z'=90
char s[500],letter[30];
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    while(scanf("%s",s))
    {
        if(s[0]=='#') break;
        int p[maxn],pos[maxn],ansp[maxn];
        int num=0,len=(int)strlen(s);
        for(char ch='A';ch<='Z';ch++)
            if(strchr(s,ch))
            {
                letter[num]=ch;//若知道字母的id编号,则可由letter数组获取该字母,以便输出
                id[ch]=num++;
            }
         vector<int> u,v;//u[i]与v[i]之间有边,u[i]和v[i]都是记录id编号
         for(int i=0;i<len;i++)
         {
             int t=i;
             i+=2;//i指向:后面的第一位
             while(i<len && s[i]!=';')
             {
                 u.push_back(id[s[t]]);
                 v.push_back(id[s[i]]);
                 i++;
             }
         }
         int width=0,ans=inf;
         for(int i=0;i<num;i++) p[i]=i;
         do{
             width=0;
             for(int i=0;i<num;i++) pos[p[i]]=i;
             for(int i=0;i<u.size();i++)
             {
                 width=max(width,abs(pos[u[i]]-pos[v[i]]));
                 if(width>=ans) break;//剪枝
             }
             if(width<ans)
             {
                 ans=width;
                 memcpy(ansp,p,sizeof(p));
             }
         }while(next_permutation(p,p+num));
         for(int i=0;i<num;i++)
             printf("%c ",letter[ansp[i]]);
         printf("-> %d\n",ans);
    }
    return 0;
}