[USACO5.5.3]Twofive

本文介绍了一种基于字母网格的游戏算法实现,通过记忆化深度优先搜索(DFS)解决寻找特定字母排列的问题。游戏要求玩家在5x5的网格中按字母顺序放置字母,并能根据数字找到对应的网格布局或反之。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Twofive
IOI 2001

In order to teach her young calvess the order of the letters in the alphabet, Bessie has come up with a game to play with them. The calves are given a 5 x 5 grid on which they can put the letters 'A'-'Y', but the one rule is that all the letters going across the columns and down the rows must be in the order they appear in the alphabet.

There are a huge number of possible grids, so Bessie decides that they will be named by the string of letters that is given by reading across each row, going down the rows. For example, the grid: 

 
     A B C D E
     F G H I J
     K L M N O
     P Q R S T 
     U V W X Y

would have the name ABCDEFGHIJKLMNOPQRSTUVWXY, which is coincidentally the first possible grid when the entire set of grids is ordered alphabetically. The second grid that meets this requirement is ABCDEFGHIJKLMNOPQRSUTVWXY, which is formed by switching the 'T' and 'U' in the above grid.

Help the calves gain bragging rights. Given a number, M, find which string is Mth in the list of all possible grids when they are sorted alphabetically, and, given a string of letters, find out what number the corresponding grid is in the list of all possible grids.

PROGRAM NAME: twofive

INPUT FORMAT

The first input line contains one of two letters, either an 'N' or a 'W'.

If the first input line contains an 'N', the second line will contain an integer, M, that corresponds to the number of a valid grid. If the first line contains a 'W', the second line will contain a string of 25 letters, which represents a valid grid.

OUTPUT FORMAT

If the input contained the number of a valid grid (first line 'N'), the output should contain a string of 25 letters on a line, which corresponds to the Mth grid in the sorted list of all possible grids.

If the input contained a string of letters indicating a grid (first line 'W'), the output should contain a single integer on a line, which corresponds to the number of the given grid in the list of all possible grids.

SAMPLE INPUT #1 (file twofive.in)

N
2

SAMPLE OUTPUT #1 (file twofive.out)

ABCDEFGHIJKLMNOPQRSUTVWXY

SAMPLE INPUT #2 (file twofive.in)

W
ABCDEFGHIJKLMNOPQRSUTVWXY

SAMPLE OUTPUT #2 (file twofive.out)

2

DFS逐位确定就行了。

ID:cqz15311
LANG:C++
PROG:twofive
*/
#include<bits/stdc++.h>
using namespace std;
int maxr[8],maxc[8],Ans[8][8],used[7*7],dp[7][7][7][7][7];
int dfs(int a,int b,int c,int d,int e,int k){
	if (~dp[a][b][c][d][e]) return dp[a][b][c][d][e];
	int rec = 0;
	if (used[k]) return dfs(a,b,c,d,e,k+1);
	if (a+1<=5 && maxr[1]<k && maxc[a+1]<k) rec+=dfs(a+1,b,c,d,e,k+1);
	if (b+1<=a && maxr[2]<k && maxc[b+1]<k) rec+=dfs(a,b+1,c,d,e,k+1);
	if (c+1<=b && maxr[3]<k && maxc[c+1]<k) rec+=dfs(a,b,c+1,d,e,k+1);
	if (d+1<=c && maxr[4]<k && maxc[d+1]<k) rec+=dfs(a,b,c,d+1,e,k+1);
	if (e+1<=d && maxr[5]<k && maxc[e+1]<k) rec+=dfs(a,b,c,d,e+1,k+1);
	//考虑之后枚举的k是递增的,因此只要满足比已经确定的大就行了 
	return dp[a][b][c][d][e] = rec;
}
void solveN(){
	int len[8],N;
	memset(len,0,sizeof(len));
	memset(used,false,sizeof(used));
	memset(maxr,0,sizeof(maxr));
	memset(maxc,0,sizeof(maxc));
	scanf("%d",&N);
	for (int i=1;i<=5;i++){
		for (int j=1;j<=5;j++){
			len[i]++;
			for (int k=1;k<=25;k++){
				if (!used[k] && k>maxr[i] && k>maxc[j]){
					used[k] = true;
					memset(dp,-1,sizeof(dp));
					dp[5][5][5][5][5] = 1;
					int tmp = dfs(len[1],len[2],len[3],len[4],len[5],1);
					maxr[i] = k;
					maxc[j] = k;
					if (tmp >= N){
						Ans[i][j] = k;
						break;
					}
					used[k] =false;
					N -= tmp;
				}
			}
		}
	}
	for (int i=1;i<=5;i++){
		for (int j=1;j<=5;j++){
			printf("%c",Ans[i][j]-1+'A');
		}
	} 
}

void solveW(){
	char s[30];
	int len[8],Ans;
	memset(len,0,sizeof(len));
	memset(maxr,0,sizeof(maxr));
	memset(maxc,0,sizeof(maxc));
	memset(used,false,sizeof(used));
	scanf("%s",s+1);
	Ans = 0;
	for (int i=1;i<=5;i++){
		for (int j=1;j<=5;j++){
			len[i]++;
			int t = (i-1)*5+j;
			for (int k=1;k<s[t] - 'A' + 1;k++){
				if (used[k] || maxr[i] > k || maxc[j] > k) continue;
				used[k] = true;
				memset(dp,-1,sizeof(dp));
				dp[5][5][5][5][5] = 1;
				int tmp1 = maxr[i];maxr[i] = k;
				int tmp2 = maxc[j];maxc[j] = k;
				Ans += dfs(len[1],len[2],len[3],len[4],len[5],1);
				maxr[i] = tmp1;
				maxc[j] = tmp2;
				used[k] = false;
			}
			maxr[i] = s[t]-'A'+1;
			maxc[j] = s[t]-'A'+1;
			used[s[t] - 'A' + 1] = true;
		}
	}
	printf("%d",Ans+1);
}

int main(){
	freopen("twofive.in","r",stdin);
	freopen("twofive.out","w",stdout);
	memset(dp,-1,sizeof(dp));
	dp[5][5][5][5][5] = 1;
	char type;
	type = getchar();
	while (type!='N' && type!='W') type = getchar(); 
	if (type == 'N') solveN(); else
					 solveW();
	puts("");
	fclose(stdin);
	fclose(stdout);
	return 0;
}
我们先考虑N的情况
考虑一个格子一个格子的填数字——那么应该填写什么数字的?
假设我们得到当前填写数字A,之后的总情况是a 
填写数字B,之后的总情况是b
填写数字C,之后的总情况是c 
考虑如果我要得到的大于(等于)a,小于b,那么显然应该填写a 
如果我要得到的大于(等于)b,小于c,那么显然应该填写c 
可以用带备忘的dfs求出上述结果。
考虑用Dp[a,b,c,d,e]分别表示第1行~第5行填了哪些数。
满足a<=b<=c<=d<=e 
那么,假设当前要填写数k
如果数k已经被填写过了,那么考虑填写下一个k 
满足比当前行的要大,比当前列的要大的位置都是可行性的。
得到一个记忆化DFS的过程。
一位一位确定就能得到结果
那么W其实比N要简单多了。
只需要考虑比这个小的有多少,也是一位一位确定,如果当前位置填写比当前小的,能够获得多少收益。
注意如果是1~5,不要开到数组[5],至少[6]防止越界。
速度很快,都是0ms 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值