• UVA 317 Hexagon


    UVA_317

        首先,先约定一下,我用a[i](0<=i<=2)降序存下了第一组数,用b[i](0<=i<=2)降序存下了第二组数,用c[i](0<=i<=2)降序存下了第三组数。

        题目的大概意思是,根据给出的3组数,每组数里面挑出1个放到piece上的指定的方位上,要求piece不能旋转,这样会得到3*3*3=27个不同的pieces,挑出其中9个pieces拼成一个六边形,要求每个方位上的5列共计15列,每列上的数都是相同的,问最大的score是多少。

        既然要求了每列都是同一个数,那么我们不妨想象成从每组数里面挑出一个数赋值给这个方位上的某一列,于是我们就有了这样一个思路,给3个方位上共15列一一赋值,如果最后的情况满足没有重复的pieces,就可以计算一下score并更新max的值。

        但问题是我们怎么判断pieces是否重复呢?我想到的一种方法是这样的,实际上如果某三列交于一点,那么这个点就代表了一个piece,因此这个piece会具有三个特征量,也即这三列的赋值序列,比如赋值序列(i,j,k),就表示三个方位上三列的值分别为a[i]、b[j]和c[k],如果27个点中任意一对赋值序列都不相同的话,自然就说明了没有重复的pieces。

        思路大体就是这样了,剩下的就是暴力枚举再加一点剪枝了。但后面我却发现无论怎么剪枝都超时……(所以在这里就不分享我的剪枝的思路了)

        当煎熬在那个怎么剪都超时的百无聊赖的时光中时,上帝突然建议我说:“你不妨打印一下最优解的构成,看看有什么规律没”,于是我照做了,结果还真发现了十分可喜的规律。

        我承认上面一段的段子是编的,不过规律是真的:①在最优解中,都存在这样的一个或若干个解,满足每个方位上中间那列都是赋的对应组的最小值,即3个方位上的中间那列的值分别为a[2]、b[2]、c[2]。②在最优解中,每组数总是最小的使用了1次,其余两个数各使用了2次,即X[2](X=a,b,c)使用了1次,X[0]、X[1]各使用了2次。

        根据上面两条规律,每个方向上需要枚举的赋值序列就只有C(4,2)=6个了,当然,还有更多的特征来减少枚举量。于是又写了一个程序,发现这些规律的剪枝效果比我前面冥思苦想的所有剪枝的效果要好千百倍。-_-||

        下面第一个程序是原始程序,方便大家用来打印最优解结构观察规律,第二个是AC了的程序。

    //dfs+剪枝,超时,但可以打印最优解的结构来观察规律
    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    int A[10], B[10], C[10], ha[5], hb[5], hc[5], a[5], b[5], c[5], max;
    int x[] = {0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4, 1, 2, 3, 4, 2, 3, 4};
    int y[] = {2, 1, 0, 3, 2, 1, 0, 4, 3, 2, 1, 0, 4, 3, 2, 1, 4, 3, 2};
    int z[] = {0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4};
    int p[] = {3, 4, 5, 4, 3};
    int n[] = {3, 7, 12, 16, 19};
    int cmp(const void *_p, const void *_q)
    {
    int *p = (int *)_p;
    int *q = (int *)_q;
    return *q - *p;
    }
    void init()
    {
    int i;
    for(i = 0; i < 3; i ++)
    scanf("%d", &a[i]);
    for(i = 0; i < 3; i ++)
    scanf("%d", &b[i]);
    for(i = 0; i < 3; i ++)
    scanf("%d", &c[i]);
    qsort(a, 3, sizeof(a[0]), cmp);
    qsort(b, 3, sizeof(b[0]), cmp);
    qsort(c, 3, sizeof(c[0]), cmp);
    }
    int checkc(int cur)
    {
    int i, j;
    for(i = 0; i < n[cur]; i ++)
    for(j = i + 1; j < n[cur]; j ++)
    {
    if(A[x[i]] == A[x[j]] && B[y[i]] == B[y[j]] && C[z[i]] == C[z[j]])
    return 0;
    }
    return 1;
    }
    int checkb(int cur)
    {
    int i, j, x1, y1, x2, y2;
    if(cur >= 1)
    for(i = 2; i <= 4; i ++)
    for(x1 = i, y1 = 0; x1 > 0 && y1 < cur; x1 --, y1 ++)
    for(x2 = x1 - 1, y2 = y1 + 1; x2 >= 0 && y2 <= cur; x2 --, y2 ++)
    if(A[x1] == A[x2] && B[y1] == B[y2])
    return 0;
    if(cur >= 2)
    for(x1 = 4, y1 = 1; x1 > 0 && y1 < cur; x1 --, y1 ++)
    for(x2 = x1 - 1, y2 = y1 + 1; x2 >= 0 && y2 <= cur; x2 --, y2 ++)
    if(A[x1] == A[x2] && B[y1] == B[y2])
    return 0;
    if(cur >= 3)
    for(x1 = 4, y1 = 2; x1 > 0 && y1 < cur; x1 --, y1 ++)
    for(x2 = x1 - 1, y2 = y1 + 1; x2 >= 0 && y2 <= cur; x2 --, y2 ++)
    if(A[x1] == A[x2] && B[y1] == B[y2])
    return 0;
    return 1;
    }
    void dfs(int cur, int st, int score)
    {
    int i, j, k;
    if(st == 2)
    {
    if(cur == 5)
    {
    if(score >= max)
    {
    printf("%d\n", score);
    printf("%d %d %d %d %d\n", A[0], A[1], A[2], A[3], A[4]);
    printf("%d %d %d %d %d\n", B[0], B[1], B[2], B[3], B[4]);
    printf("%d %d %d %d %d\n", C[0], C[1], C[2], C[3], C[4]);
    puts("");
    max = score;
    }
    return ;
    }
    for(i = 0; i < 3; i ++)
    {
    if(hc[i] >= 2)
    continue;
    ++ hc[i];
    C[cur] = i;
    if(checkc(cur))
    dfs(cur + 1, st, score + p[cur] * c[i]);
    -- hc[i];
    }
    }
    else if(st == 1)
    {
    for(i = 0; i < 3; i ++)
    {
    if(hb[i] >= 2)
    continue;
    ++ hb[i];
    B[cur] = i;
    if(checkb(cur))
    {
    if(cur == 4)
    dfs(0, st + 1, score + p[cur] * b[i]);
    else
    dfs(cur + 1, st, score + p[cur] * b[i]);
    }
    -- hb[i];
    }
    }
    else
    {
    for(i = 0; i < 3; i ++)
    {
    if(ha[i] >= 2)
    continue;
    ++ ha[i];
    A[cur] = i;
    if(cur == 4)
    dfs(0, st + 1, score + p[cur] * a[i]);
    else
    dfs(cur + 1, st, score + p[cur] * a[i]);
    -- ha[i];
    }
    }
    }
    void solve()
    {
    int i, j, k;
    max = 0;
    memset(ha, 0, sizeof(ha));
    memset(hb, 0, sizeof(hb));
    memset(hc, 0, sizeof(hc));
    dfs(0, 0, 0);
    printf("%d\n", max);
    }
    int main()
    {
    int t, tt;
    scanf("%d", &t);
    for(tt = 0; tt < t; tt ++)
    {
    init();
    printf("Test #%d\n", tt + 1);
    solve();
    printf("\n");
    }
    return 0;
    }

     

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    int A[10], B[10], C[10], a[5], b[5], c[5];
    int p[] = {3, 4, 5, 4, 3};
    int d[][5] = {{0, 0, 2, 1, 1}, {0, 1, 2, 0, 1}, {0, 1, 2, 1, 0},
    {1, 0, 2, 0, 1}, {1, 0, 2, 1, 0}, {1, 1, 2, 0, 0}};
    int cmp(const void *_p, const void *_q)
    {
    int *p = (int *)_p;
    int *q = (int *)_q;
    return *q - *p;
    }
    void init()
    {
    int i;
    for(i = 0; i < 3; i ++)
    scanf("%d", &a[i]);
    for(i = 0; i < 3; i ++)
    scanf("%d", &b[i]);
    for(i = 0; i < 3; i ++)
    scanf("%d", &c[i]);
    qsort(a, 3, sizeof(a[0]), cmp);
    qsort(b, 3, sizeof(b[0]), cmp);
    qsort(c, 3, sizeof(c[0]), cmp);
    }
    void solve()
    {
    int i, j, k, r, res, max = 0;
    for(i = 0; i < 6; i ++)
    for(j = 0; j < 6; j ++)
    {
    if(j == i)
    continue;
    for(k = 0; k < 6; k ++)
    {
    if(k == i || k == j)
    continue;
    res = 0;
    for(r = 0; r < 5; r ++)
    {
    A[r] = d[i][r], B[r] = d[j][r], C[r] = d[k][r];
    res += p[r] * (a[A[r]] + b[B[r]] + c[C[r]]);
    }
    if(res > max)
    max = res;
    }
    }
    printf("%d\n", max);
    }
    int main()
    {
    int t, tt;
    scanf("%d", &t);
    for(tt = 0; tt < t; tt ++)
    {
    init();
    printf("Test #%d\n", tt + 1);
    solve();
    printf("\n");
    }
    return 0;
    }

     


  • 相关阅读:
    ajax小白理解
    Once more
    win滚动条样式修改
    NOIP2018游记
    Stirling数笔记
    【Start From Here】HNOI2018 滚粗记
    6面相对象
    5方法定义及调用
    Java4数组
    Java3流程控制语句
  • 原文地址:https://www.cnblogs.com/staginner/p/2298304.html
Copyright © 2020-2023  润新知