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;
}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值