PAT甲级真题 A1025 PAT Ranking

 

题目概述:Programming Ability Test (PAT) is organized by the College of Computer Science and Technology of Zhejiang University. Each test is supposed to run simultaneously in several places, and the ranklists will be merged immediately after the test. Now it is your job to write a program to correctly merge all the ranklists and generate the final rank.

Input Specification:
Each input file contains one test case. For each case, the first line contains a positive number N (≤100), the number of test locations. Then N ranklists follow, each starts with a line containing a positive integer K (≤300), the number of testees, and then K lines containing the registration number (a 13-digit number) and the total score of each testee. All the numbers in a line are separated by a space.

Output Specification:
For each test case, first print in one line the total number of testees. Then print the final ranklist in the following format: registration_number final_rank location_number local_rank

The locations are numbered from 1 to N. The output must be sorted in nondecreasing order of the final ranks. The testees with the same score must have the same rank, and the output must be sorted in nondecreasing order of their registration numbers.
Sample Input:
2
5
1234567890001 95
1234567890005 100
1234567890003 95
1234567890002 77
1234567890004 85
4
1234567890013 65
1234567890011 25
1234567890014 100
1234567890012 85

Sample Output:
9
1234567890005 1 1 1
1234567890014 1 2 1
1234567890001 3 1 2
1234567890003 3 1 2
1234567890004 5 1 4
1234567890012 5 2 2
1234567890002 7 1 5
1234567890013 8 2 3
1234567890011 9 2 4
题目大意:有N个考场,每个考场里有K个学生,依次输入这些学生的考号与成绩,并按照成绩由高到低(如果成绩相同则按字典序由低到高)排序,并依次输出该学生成绩的总排名,考场号,以及在考场的排名。
题解:使用结构体储存学生信息,我的结构体共有5个变量,当然也有用4个的

struct student
{
	char number[105];
	int countnumber;
	int lanknumber;
	int all;
	int score;
};

 

大致思路为使用两次sort排序,先在本考场内进行一次排序,得出学生在考场的位序,其次在全部学生进行一次排序。cmp构造如下:

bool cmp(student a, student b)
{
	if (a.score != b.score)
		return a.score > b.score;
	if (a.score == b.score)
		return strcmp(a.number, b.number) < 0;
}

 

注意在PTA上提交时要加上cstring头文件,否则会编译错误
AC代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include <cstring> 
using namespace std;
struct student
{
	char number[105];
	int countnumber;
	int lanknumber;
	int all;
	int score;
};
bool cmp(student a, student b)
{
	if (a.score != b.score)
		return a.score > b.score;
	if (a.score == b.score)
		return strcmp(a.number, b.number) < 0;
}
int main()
{
	struct student box[30005];
	int count, m = 0, n = 0, now1 = 1, now2 = 1;
	int everycount[105];
	cin >> count;
	for (int t = 0; t < count; t++)
	{
		cin >> everycount[m];
		for (int t1 = 0; t1 < everycount[m]; t1++)
		{
			cin >> box[n].number >> box[n].score;
			box[n].countnumber = m+1;
			n++;
		}
		sort(box + n - everycount[m], box + n, cmp);
		now1 = 1, now2 = 1;
		for (int t3 = n - everycount[m]; t3 < n; t3++)
		{
			if (t3 != 0 && box[t3 - 1].score == box[t3].score)
				box[t3].lanknumber = box[t3 - 1].lanknumber;
			else
				box[t3].lanknumber = now2;
			now2++;
		}
		m++;
		
	}
	sort(box, box + n, cmp);
	now1 = 1, now2 = 1;
	for (int t3 = 0; t3 < n; t3++)
	{
		if (t3 != 0 && box[t3 - 1].score == box[t3].score)
			box[t3].all = box[t3 - 1].all;
		else
			box[t3].all = now2;
		now2++;
	}
	cout << n << endl;
	for (int t5 = 0; t5 < n; t5++)
		cout << box[t5].number << " " << box[t5].all << " " << box[t5].countnumber << " " << box[t5].lanknumber << endl;

}
另外贴一篇五子棋估值函数,今年由于疫情的原因,计算机博弈赛在网上举行

估值算法。要求给定棋盘上一个点,求出该点在当前棋局下的权值。若在该点落子后更容易接近胜利,则该点权值就高,越接近5子相连,权值越高。

  首先考虑每个点有8个方向可以连子,每个方向上又有多种连子棋型,如活四、活三、死三等,而这些子又可能属于己方或者对方。活四与活三的权值自然不同。而同样是活三,己方的活三与对方的活三权值也不同,这样才能实现攻守的策略。假如现在棋局上同时有己方的活三和对方的活三,此时轮到我方落子,则正常情况下应当在己方活三上落子,使之成为活四,从而获胜。则计算机在判断棋局时,遇到己方活三,权值应当较高,遇到对方活三,权值应当较低。

  以上即是对于估值函数所应达到的要求的分析。

 

方向问题

  由于着眼处在于对棋型的判断,而不是方向,所以首先应该想个方法把方向问题先解决掉,这样在棋型判断时就能够对各个方向进行比较统一的处理,不至于棋型判断时对每个方向都写一段代码。

  继续分析,在判断棋型时,着眼点在于棋子的相对位置,而常见棋型都呈线形排列,所以这个相对位置也就是顺序。相对位置、顺序,很容易想到要用一维的坐标解决。若取某一斜列(行、列),假设当前点的坐标为0,取右下(下、右、右上)为正方向,则在该斜列(行、列)上各点都能得到相应的坐标。

代码如下:

int getLine(Point p, int i, int j) { // p:当前点 i:方向 j:坐标相对值
int x = p.x, y = p.y;
switch (i) {  //对8个方向的处理
case 1 :
x = x + j;
break;
case 2 :
x = x + j;
y = y + j;
break;
...
...
case 8 :
x = x + j;
y = y - j;
}
if (x < 0 || y < 0 || x > 14 || y > 14) { // 越界处理 返回-1
return -1;
}
return box.getFlag(x,y);
}
}

int evaluate(Point p, int me,int plyer) { /* me:我的代号;  plyer:当前计算的player的代号;*/

        int value = 0;

        int numoftwo=0;

     for (int i = 1; i <= 8; i++) { // 8个方向

            // 活四       01111*      *代表当前空位置    0代表其他空位置

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) == plyer && getLine(p, i, -4) == plyer

                    && getLine(p, i, -5) == 0) {

                value += 300000;

                if(me!=plyer){value-=500;}

                System.out.print("+ 300000");

                continue;

              }

       ...

            //计算011*0或111*0的个数

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) != 3-plyer&&getLine(p,i,1)!=3-plyer) {

                numoftwo++;

             }

        ...

      }

    if(numoftwo>=2){

      value+=3000;

      if(me!=plyer){

         value-=100;

        }

      }

    return value;

}

根据不同位置判断权值:

for (int i = 1; i <= 8; i++) { // 8个方向

            // 活四 01111* *代表当前空位置  0代表其他空位置    下同

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) == plyer && getLine(p, i, -4) == plyer

                    && getLine(p, i, -5) == 0) {

                value += 300000;

                if(me!=plyer){value-=500;}

                continue;

            }

            // 死四A 21111*

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) == plyer && getLine(p, i, -4) == plyer

                    && (getLine(p, i, -5) == 3 - plyer||getLine(p, i, -5) == -1)) {

                value += 250000;

                if(me!=plyer){value-=500;}

                continue;

            }

            // 死四B 111*1

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) == plyer && getLine(p, i, 1) == plyer) {

                value += 240000;

                if(me!=plyer){value-=500;}

                continue;

            }

            // 死四C 11*11

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, 1) == plyer && getLine(p, i, 2) == plyer) {

                value += 230000;

                if(me!=plyer){value-=500;}

                continue;

            }

            // 活三 近3位置 111*0

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) == plyer) {

                if (getLine(p, i, 1) == 0) {

                    value += 750;

                    if (getLine(p, i, -4) == 0) {

                        value += 3150;

                        if(me!=plyer){value-=300;}

                    }

                }

                if ((getLine(p, i, 1) == 3 - plyer||getLine(p, i, 1) == -1) && getLine(p, i, -4) == 0) {

                    value += 500;

                }

                continue;

            }

            // 活三 远3位置 1110*

            if (getLine(p, i, -1) == 0 && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) == plyer && getLine(p, i, -4) == plyer) {

                value += 350;

                continue;

            }

            // 死三 11*1

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, 1) == plyer) {

                value += 600;

                if (getLine(p, i, -3) == 0 && getLine(p, i, 2) == 0) {

                    value += 3150;

                    continue;

                }

                if ((getLine(p, i, -3) == 3 - plyer||getLine(p, i, -3) == -1) && (getLine(p, i, 2) == 3 - plyer||getLine(p, i, 2) == -1)) {

                    continue;

                } else {

                    value += 700;

                    continue;

                }

            }

            //活二的个数

            if (getLine(p, i, -1) == plyer && getLine(p, i, -2) == plyer

                    && getLine(p, i, -3) != 3-plyer&&getLine(p,i,1)!=3-plyer) {

                numoftwo++;

            }

            //其余散棋

            int numOfplyer = 0; // 因为方向会算两次?

            for (int k = -4; k <= 0; k++) { // ++++* +++*+ ++*++ +*+++ *++++

                int temp = 0;

                for (int l = 0; l <= 4; l++) {

                    if (getLine(p, i, k + l) == plyer) {

                        temp++;

                    } else

                        if (getLine(p, i, k + l) == 3 - plyer

                                || getLine(p, i, k + l) == -1) {

                        temp = 0;

                        break;

                    }

                }

                numOfplyer += temp;

            }

            value += numOfplyer * 15;

            if (numOfplyer != 0) {

            }

        }

        if(numoftwo>=2){

            value+=3000;

            if(me!=plyer){

                value-=100;

                }

            }

        return value;

 

 

posted on 2020-08-27 09:34  AIERSTOM  阅读(211)  评论(0编辑  收藏  举报

导航