题目地址:
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=253
题目描述:
Hexagon |
Consider a game board consisting of 19 hexagonal fields, as shown in the figure below. We can easily distinguish three main directions in the shape of the board: from top to bottom, from top-left to bottom-right, and from top-right to bottom-left. For each of these primary directions, the board can be viewed as a series of rows, consisting of 3, 4, 5, 4, and 3 fields, respectively.
The game board has to be completely covered using a set of hexagonal pieces. Each piece carries three numbers, one for every primary board direction. Only three different numbers are used for each direction. Every possible combination of three numbers for all three directions is assigned to a piece, leading to a set of 27 unique pieces. (The board in the above figure is still in the process of being covered.)
The score of a board is calculated as the sum of all 15 row scores (5 rows for each primary direction). The row scores are calculated as follows: if all pieces in a row carry the same number for the direction of the row, the row score is this number multiplied by the number of pieces in the row. Otherwise (the pieces carry different numbers in the row direction) the row score is zero. Note that the pieces may not be rotated. For example, the score of the leftmost row in the figure is , the score of the row to its right is .
While in the real game the pieces are chosen randomly and the set of pieces is fixed, we are interested in the highest possible score for a given set of numbers for each direction, when all pieces in a row carry the same number for the direction of the row. This means you have to choose those 19 pieces that result in the highest score.
The first line of the input file contains an integer n which indicates the number of test cases. Each test case consists of three lines containing three integers each. Each of these three line contains the numbers for a single primary direction. From these numbers the set of pieces is generated.
For each test case output a line containing the number of the case (`Test #1', `Test #2', etc.), followed by a line containing the highest possible score for the given numbers. Add a blank line after each test case.
1 9 4 3 8 5 2 7 6 1
Test #1 308题意:
给出3组数,每组数有3个,每组数只能填一个基本方向(上下,左斜上,右斜下),分别冲3组数中各取一个数,组成一个小六边形,对角的数字相同且同一组的数字,让你用最多组成的27个小六边形,挑19个不重复的出来,组成一个大六边形,使得目标值最大,目标值等于3个基本方向上,每个列的数的综合,有一列的数不相同的,则该列权值为0。
题解:
三种方法:1、DFS+剪枝(TLE,可用于规律发现)2、规律推导(下标的规律组合 全排)3、规律推导(各个方向上的数量有规律 组合全排)
一、DFS+剪枝,以选中的小6变形为对象,当DFS到19时 停止搜索,计算目标值。这个表示剪了n久的枝还是超时,也想不出实质性的关键剪枝,都是些无关痛痒的剪枝,但是可以利用这个程序观察最大值得元素组成和分布的规律,后来在看到网上关于规律发现的总结才过掉,其规律总结为:
三个方向上的构成只可能是以下这一种可能性:一个方向上三个数分别乘以5(=5),6(=3+3),8(=4+4);另外两个方向上三个数分别乘以5(=5),7(=3+4),7(=3+4)
二、规律推导,将问题转型为:为了让每列值中都是相同的,所以我们可以这样看待问题,即在第一组数中选择数字填入5个容器中(5列,每列数量分别为3 4 5 4 3),这样有3个方向,所以有3组有5个容器的二维序列,这样我们只要求出这个二维序列代表值的总和就是所谓的目标值了。规律参考了网上:将输入的每组值,按组内从小到大排列,然后利用一、DFS+剪枝的标准程序,生成一定的样例,输出选中输入数的相应下标组成的二维矩阵,可以发现最大值的组成都是有固定的几组下标{1,1,0,2,2},{1,2,0,1,2},{1,2,0,2,1},{2,1,0,1,2},{2,1,0,2,1},{2,2,0,1,1}组成。
下面给出输入样例得到的输出:
308 1 0 2 0 1 0 0 2 1 1 0 1 2 0 1 308 1 0 2 0 1 0 0 2 1 1 1 0 2 1 0 308 1 0 2 0 1 0 1 2 0 1 0 0 2 1 1 308 1 0 2 0 1 0 1 2 0 1 1 1 2 0 0 308 1 0 2 0 1 1 0 2 1 0 0 0 2 1 1 308 1 0 2 0 1 1 0 2 1 0 1 1 2 0 0 308 1 0 2 0 1 1 1 2 0 0 0 1 2 0 1 308 1 0 2 0 1 1 1 2 0 0 1 0 2 1 0
三、规律推导,同理,将问题转换成填充一个3*5的二维矩阵上,即如何从输入数中选择数值填入矩阵中,使其和最大。这次还是通过一、程序找规律,这次我们把矩阵单元中的下标换成输入的具体数值,下面将输出的结果打印供分析规律:
308
4 9 3 9 4
8 5 2 8 5
7 7 1 6 6
308
4 9 3 9 4
5 8 2 5 8
7 7 1 6 6
308
4 9 3 9 4
5 5 2 8 8
7 6 1 7 6
308
4 9 3 9 4
8 8 2 5 5
7 6 1 7 6
308
4 9 3 9 4
5 5 2 8 8
6 7 1 6 7
308
4 9 3 9 4
8 8 2 5 5
6 7 1 6 7
308
4 9 3 9 4
8 5 2 8 5
6 6 1 7 7
308
4 9 3 9 4
5 8 2 5 8
6 6 1 7 7
5 6 8 5 7 7 5 7 7 5 7 7 5 6 8 5 7 7 5 7 7 5 7 7 5 6 8然后用这3个分布规律的矩阵算出所有的情况的总和,从中取最大即可。
证明:关于上面两个的证明,目前没想到什么方法去证明这个规律定理,怎么证呢??? 纠结。。。。。
代码:
一、DFS+剪枝(TLE)
/* matrix: 0 0 x 0 0 0 x 0 x 0 x 0 x 0 x 0 x 0 x 0 x 0 x 0 x 0 x 0 x 0+ x 0 x 0 x 0 x 0 x 0 0 0 x 0 0 choose the DFS's depth or object is very important hwo to prune this DFS???????? */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <algorithm> #include <iostream> using namespace std; typedef struct pie { /* data */ int tb;//top-bottom int lr;//top left-bottom right int rl;//top right-bottom left pie() { tb=0; lr=0; rl=0; } }pie,*pielink; pie pieset[27+5];//3*3*3=27,begin with 1,pieset[0] is no initialzed piece bool vis[27+5]={false};//the pie set of the vis array,begin with 1 int num[3][3]={0};//input num array int cases=0;//the test case number of the input int graph[9][5];//the graph of the case.the place cast trans to this graph or matrix please look at the top of this source,the value is the index of the pieset int sum=0;//the score sum int maxsum=0;//the max of the sums int partsum=0;//use for prune int partmaxsum=0;//use for prune int sumstack[19+5]={0};//record the per DFS per sum,assure that per DFS sum >maxsum then this sum at end must be the true maxsum,begin with 1 int maxsumstack[19+5]={0}; bool graphvis[9][5]= { {false,false,true,false,false}, {false,true,false,true,false}, {true,false,true,false,true}, {false,true,false,true,false}, {true,false,true,false,true}, {false,true,false,true,false}, {true,false,true,false,true}, {false,true,false,true,false}, {false,false,true,false,false} }; int ablecoor[19][2]=//the avaliable coordinate record { {2,0},{4,0},{6,0}, {1,1},{3,1},{5,1},{7,1}, {0,2},{2,2},{4,2},{6,2},{8,2}, {1,3},{3,3},{5,3},{7,3}, {2,4},{4,4},{6,4} }; /*compare for the sort*/ bool cmp(int a,int b) { return(a>b); } /*compare for the sort pieset*/ bool cmppie(pie a,pie b) { return((a.tb+a.lr+a.rl)>(b.tb+b.lr+b.rl)); } /*calculate the sum score,the IsCheck has check the a row =0 's case,so we need not think about it*/ int CalcPie() { int sum=0; //top - bottom sum+=pieset[graph[2][0]].tb+pieset[graph[4][0]].tb+pieset[graph[6][0]].tb;//3 sum+=pieset[graph[1][1]].tb+pieset[graph[3][1]].tb+pieset[graph[5][1]].tb+pieset[graph[7][1]].tb;//4 sum+=pieset[graph[0][2]].tb+pieset[graph[2][2]].tb+pieset[graph[4][2]].tb+pieset[graph[6][2]].tb+pieset[graph[8][2]].tb;//5 sum+=pieset[graph[1][3]].tb+pieset[graph[3][3]].tb+pieset[graph[5][3]].tb+pieset[graph[7][3]].tb;//4 sum+=pieset[graph[2][4]].tb+pieset[graph[4][4]].tb+pieset[graph[6][4]].tb;//3 //topleft-bottomright sum+=pieset[graph[0][2]].lr+pieset[graph[1][3]].lr+pieset[graph[2][4]].lr; sum+=pieset[graph[1][1]].lr+pieset[graph[2][2]].lr+pieset[graph[3][3]].lr+pieset[graph[4][4]].lr; sum+=pieset[graph[2][0]].lr+pieset[graph[3][1]].lr+pieset[graph[4][2]].lr+pieset[graph[5][3]].lr+pieset[graph[6][4]].lr; sum+=pieset[graph[4][0]].lr+pieset[graph[5][1]].lr+pieset[graph[6][2]].lr+pieset[graph[7][3]].lr; sum+=pieset[graph[6][0]].lr+pieset[graph[7][1]].lr+pieset[graph[8][2]].lr; //topright-bottomleft sum+=pieset[graph[0][2]].rl+pieset[graph[1][1]].rl+pieset[graph[2][0]].rl; sum+=pieset[graph[1][3]].rl+pieset[graph[2][2]].rl+pieset[graph[3][1]].rl+pieset[graph[4][0]].rl; sum+=pieset[graph[2][4]].rl+pieset[graph[3][3]].rl+pieset[graph[4][2]].rl+pieset[graph[5][1]].rl+pieset[graph[6][0]].rl; sum+=pieset[graph[4][4]].rl+pieset[graph[5][3]].rl+pieset[graph[6][2]].rl+pieset[graph[7][1]].rl; sum+=pieset[graph[6][4]].rl+pieset[graph[7][3]].rl+pieset[graph[8][2]].rl; return(sum); } /*check the point that his neighbour 's the direction value is equal*/ bool IsCheck(int i,int j,int k) { int nexti=0,nextj=0,nextk=0;//note that ths place is sorted so we do not think about bottom, topright , bottomright //top - bottom next //top nexti=i-1; nextj=j; nextk=0; while(nexti>=0) { if(graphvis[nexti][nextj]) { if(graph[nexti][nextj]>=0) { nextk=graph[nexti][nextj]; if(pieset[k].tb!=pieset[nextk].tb) { return(false); } } else { break;//the DFS's path is sorted direction } } nexti--; } //top left nexti=i-1; nextj=j-1; nextk=0; while(nexti>=0&&nextj>=0) { if(graphvis[nexti][nextj]) { if(graph[nexti][nextj]>=0) { nextk=graph[nexti][nextj]; if(pieset[k].lr!=pieset[nextk].lr) { return(false); } } else { break;//the DFS's path is sorted direction } } nexti--; nextj--; } //bottom left nexti=i+1; nextj=j-1; nextk=0; while(nexti<=9-1&&nextj>=0) { if(graphvis[nexti][nextj]) { if(graph[nexti][nextj]>=0) { nextk=graph[nexti][nextj]; if(pieset[k].rl!=pieset[nextk].rl) { return(false); } } else { break;//the DFS's path is sorted direction } } nexti++; nextj--; } return(true); } /*output the maze*/ int outputmaze() { //top - bottom printf("%d %d %d %d %d\n",pieset[graph[2][0]].tb,pieset[graph[1][1]].tb,pieset[graph[0][2]].tb,pieset[graph[1][3]].tb,pieset[graph[2][4]].tb); //topleft - bottomright printf("%d %d %d %d %d\n",pieset[graph[0][2]].lr,pieset[graph[1][1]].lr,pieset[graph[2][0]].lr,pieset[graph[4][0]].lr,pieset[graph[6][0]].lr); //topright - botomleft printf("%d %d %d %d %d\n", pieset[graph[0][2]].rl,pieset[graph[1][3]].rl,pieset[graph[2][4]].rl,pieset[graph[4][4]].rl,pieset[graph[6][4]].rl); return(0); } /*DFS the graph,cur is the count of the used piece and coorind is the index of the ablecoor[]*/ int DFS(int cur,int coorind) { if(cur>=19) { sum=CalcPie(); if(sum==308) printf("%d\n",sum ); if(sum==308) outputmaze(); if(sum>maxsum) { maxsum=sum;//update the max sum } } else { int i=0; int nextm=ablecoor[coorind][0],nextn=ablecoor[coorind][1];//the next coordinate //find the place position for(i=1;i<=27;i++) { if(!vis[i]) { if(IsCheck(nextm,nextn,i)) { vis[i]=true; graph[nextm][nextn]=i; partsum+=pieset[i].tb+pieset[i].lr+pieset[i].rl; DFS(cur+1,coorind+1); partsum-=pieset[i].tb+pieset[i].lr+pieset[i].rl; graph[nextm][nextn]=0; vis[i]=false; } } } } return(0); } /*for test*/ int test() { //test memset(-1),memset(-1) and memset(0) can use for the int array return(0); } /*main process*/ int MainProc() { int t=0,i=0,j=0,k=0; scanf("%d",&cases); for(t=1;t<=cases;t++) { for(i=0;i<=2;i++) { for(j=0;j<=2;j++) { scanf("%d",&num[i][j]); } //sort(num[i],num[i]+3,cmp);//DFS prune ,sort the bit to small,place the bit to the front } //init for(i=0;i<=2;i++)//27 kinds of the piece,i map the first row of the num array,j map second ,k map third { for(j=0;j<=2;j++) { for(k=0;k<=2;k++) { //three dimension to the one dimension int ind=i+j*3+k*9+1;//begin with 1 pieset[ind].tb=num[0][i]; pieset[ind].lr=num[1][j]; pieset[ind].rl=num[2][k]; } } } //sort the pieset,according to the sum tb+lr+rl,DFS prune //sort(pieset+1,pieset+28,cmppie);//sort(pieset[1],pieset[27],cmppie); is error written,begin with 1 memset(vis,false,sizeof(vis)); memset(graph,0,sizeof(graph)); memset(sumstack,0,sizeof(sumstack)); memset(maxsumstack,0,sizeof(maxsumstack)); sum=0; maxsum=0; partsum=0; partmaxsum=0; DFS(0,0);//cur is the count of the pieset cur<=19 printf("Test #%d\n%d\n\n",t ,maxsum); } return(0); } int main(int argc, char const *argv[]) { /* code */ MainProc(); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <iostream> #include <algorithm> using namespace std; int pie[3][3]={0};//the input number int indexpie[6][6]= { {1,1,0,2,2},{1,2,0,1,2},{1,2,0,2,1},{2,1,0,1,2},{2,1,0,2,1},{2,2,0,1,1} };//the value is the index of the pie array int rowcol[5]={3,4,5,4,3}; int maxs=0;//the max of the sum int sum=0;//the now sum of the score board int cases=0;//the number of the test case /*for test*/ int test() { return(0); } /*main process*/ int MainProc() { int i=0,j=0,k=0,t=0,h=0; scanf("%d",&cases); for(t=1;t<=cases;t++) { for(i=0;i<=3-1;i++) { for(j=0;j<=3-1;j++) { scanf("%d",&pie[i][j]); } sort(pie[i],pie[i]+3);//sort the value per row } //init sum=0; maxs=-1; //conbine the all cases for the indexpie for(i=0;i<=6-1;i++) { for(j=0;j<=6-1;j++) { for(k=0;k<=6-1;k++) { if(i==j||j==k||i==k)//no repeat { continue; } //get the value as the pie 's index sum=0; for(h=0;h<=6-1;h++) { sum+=(pie[0][indexpie[i][h]]+pie[1][indexpie[j][h]]+pie[2][indexpie[k][h]])*rowcol[h]; } if(sum>maxs) { maxs=sum; } } } } printf("Test #%d\n%d\n\n",t,maxs ); } return(0); } int main(int argc, char const *argv[]) { /* code */ MainProc(); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; int num[3][3]={0}; int cnt[3][3][3]=//map to the sorted row 3 numbers { {{5,6,8},{5,7,7},{5,7,7}}, {{5,7,7},{5,6,8},{5,7,7}}, {{5,7,7},{5,7,7},{5,6,8}} }; int cases=0;//the count of the test /*for test*/ int test() { return(0); } /*main process*/ int MainProc() { int t=0,i=0,j=0,k=0; scanf("%d",&cases); for(t=1;t<=cases;t++) { for(i=0;i<=2;i++) { for(j=0;j<=2;j++) { scanf("%d",&num[i][j]); } sort(num[i],num[i]+3); } int sum=0; int maxsum=0; for(k=0;k<=2;k++)//cnt[0] map to num[k] { sum=0; for(i=0;i<=2;i++) { for(j=0;j<=2;j++) { sum+=num[i][j]*cnt[k][i][j]; } } if(sum>maxsum) { maxsum=sum; } } printf("Test #%d\n%d\n\n",t,maxsum); } return(0); } int main(int argc, char const *argv[]) { /* code */ MainProc(); return 0; }