UVA140

给出一个图,找出其中的最小带宽的排列。具体要求见传送门:UVa140

这题有些小技巧可以简化代码的编写。

本题的实现参考了刘汝佳老师的源码,的确给了我许多启发,感谢刘老师。

思路:

建立双射关系:从字符A到字符Z遍历输入的字符串,用strchr函数将输入中出现的字符找出,并将找出的字符进行编号,用letter和id分别存储字符和对应的编号
降维:输入中给出的,是类似于邻接表形式的二维形式,如果我们用二维数据结构,将增加处理时对于输出细节的处理难度,用 2个 vector将输出降低到1维,简化了计算Bandwidth时的代码,实际上让我们更加有的放矢
存储必要信息——位置:数组pos每个下标代表字母编号,存储的是对应的位置下标,便于计算时寻找位置。
剪枝:减去不必要的计算(虽然对于本题而言不是必须的)
库函数的使用:memcpy,strchr,strlen,next_permutation的使用简化了代码,突出了逻辑部分。

#include<cstdio>
#include<vector>
#include<cstring>
#include<map>
//#include<sstream>
using namespace std;
const int maxn = 9 + 1, INF = 1000;
vector<int> G[maxn];
map<char, int> ID;
map<int, char> antiID;
int A[maxn];
int n;
int k;
int ans[maxn];
int pos[maxn];
//int node;
void dfs(int cur, int tmp) //tmp为解答树每条树枝特有的属性,为实现这种性质需将其作为每个递归内部定义变量,作为参数传递
{
    if (cur > n) //递归终止条件必须有
    {
        if (k > tmp)
        {
            k = tmp;
            memcpy(ans, A, sizeof(ans));
        }
        return;
    }
    for (int i = 0; i < n; i++)
    {
        if (pos[i] > -1) //重复出现
            continue;
        int cnt = 0;
        for (int j = 0; j < G[i].size(); j++)
        {
            int& v = G[i][j];
            if (pos[v] > -1)
            {
                /*for (int m = 0; m < cur; m++)
                {
                if (A[m] == v)
                {
                if ((cur - 1 - m) >= k)  //剪枝
                return;
                if ((cur - 1 - m) > tmp)
                tmp = (cur - 1 - m);
                break;
                }
                }*/
                if ((cur - 1 - pos[v]) >= k)  //剪枝//用pos数组记录排列
                    return;
                if ((cur - 1 - pos[v]) > tmp)
                    tmp = (cur - 1 - pos[v]);
                cnt++;
            }
        }
        if ((G[i].size() - cnt) >= k) //剪枝
                                      //return;
            continue; //注意回溯或剪枝对应的return或continue的选择使用
        A[cur - 1] = i;
        pos[i] = cur - 1;
        dfs(cur + 1, tmp);
        A[cur - 1] = -1;  //全局变量在出口处修改
        pos[i] = -1;
    }
}

int main()
{
    char input[1000];
    while (scanf("%s", input) == 1 && input[0] != '#')
    {
        memset(ans, 0, sizeof(ans));
        memset(A, -1, sizeof(A));
        memset(pos, -1, sizeof(pos));
        for (int i = 0; i < 8; i++)
            G[i].clear();
        n = 0;
        for (char i = 'A'; i <= 'H'; i++)
        {
            if (strchr(input, i) != NULL)  //输入处理,注意输入不一定从A开始,甚至不包含A
            {
                ID[i] = n;
                antiID[n++] = i;
            }
        }


        int len = strlen(input), p = 0, q = 0;
        //vector<int> u, v;  //建图方式
        for (;;) 
        {
            while (p < len && input[p] != ':') //输入处理
                p++;
            if (p == len) 
                break;
            while (q < len && input[q] != ';') 
                q++;
            for (int i = p + 1; i < q; i++) 
            {
                G[ID[input[p - 1]]].push_back(ID[input[i]]);
                G[ID[input[i]]].push_back(ID[input[p - 1]]);
            }
            p++; q++;
        }

        k = INF;
        dfs(1, -1);
        for (int i = 0; i < n; i++)
            printf("%c ", antiID[ans[i]]);
        if (n == 1)
            printf("-> 0\n");
        else
            printf("-> %d\n", k);
    }
}
/*int main() {
 {
// 计算结点个数并给字母编号
int n = 0;
for (char ch = 'A'; ch <= 'Z'; ch++)

id[ch] = n++;
letter[id[ch]] = ch;
}*/

WA待改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值