CodeForces 761C Dasha and Password

C. Dasha and Password
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

After overcoming the stairs Dasha came to classes. She needed to write a password to begin her classes. The password is a string of length n which satisfies the following requirements:

  • There is at least one digit in the string,
  • There is at least one lowercase (small) letter of the Latin alphabet in the string,
  • There is at least one of three listed symbols in the string: '#', '*', '&'.

Considering that these are programming classes it is not easy to write the password.

For each character of the password we have a fixed string of length m, on each of these n strings there is a pointer on some character. The i-th character displayed on the screen is the pointed character in the i-th string. Initially, all pointers are on characters with indexes 1in the corresponding strings (all positions are numbered starting from one).

During one operation Dasha can move a pointer in one string one character to the left or to the right. Strings are cyclic, it means that when we move the pointer which is on the character with index 1 to the left, it moves to the character with the index m, and when we move it to the right from the position m it moves to the position 1.

You need to determine the minimum number of operations necessary to make the string displayed on the screen a valid password.

Input

The first line contains two integers nm (3 ≤ n ≤ 50, 1 ≤ m ≤ 50) — the length of the password and the length of strings which are assigned to password symbols.

Each of the next n lines contains the string which is assigned to the i-th symbol of the password string. Its length is m, it consists of digits, lowercase English letters, and characters '#', '*' or '&'.

You have such input data that you can always get a valid password.

Output

Print one integer — the minimum number of operations which is necessary to make the string, which is displayed on the screen, a valid password.

Examples
input
3 4
1**2
a3*0
c4**
output
1
input
5 5
#*&#*
*a1c&
&q2w*
#a3c#
*&#*&
output
3
Note

In the first test it is necessary to move the pointer of the third string to one left to get the optimal answer.

In the second test one of possible algorithms will be:

  • to move the pointer of the second symbol once to the right.
  • to move the pointer of the third symbol twice to the right.


这个题刚开始的时候光只是题意就坑了我很久。

题意:这个题刚开始的时候就告诉了我们正确密码的标准格式:1.至少要有一个数字。2.至少要有一个小写字母。3,至少要有一个特殊字符。(特殊字符指‘#’,‘&’,‘*’。)然后就是在输入中会告诉我们n个长度为m的字符串,每个字符串都被指针会指向第一个字母。然后每次都能移动一个指针,而且只能向左或向右移动一个位置。同时这些字符串是成环状的,例如:如果刚开始的时候指针指向第一个字符,可以向左移动一个位置指向最后一个字符。现在把每个字符串中被指的字符取出组成一个新密码,要求新密码符合标准格式。问最少只需移动多少次即可。

思路:首先我们要明白两点,1.如果我们要符合标准格式就只需要用到其中的三个字符串即可。2.在每一个字符串中对于每一个条件我们需找出一个最近的即可。例如:在字符串1g1g##中对于第一个条件只需移动0步指向第一个字符即可而不用管第四个数字字符。对于第二个条件只需向右移动1步指向第二个字符g即可。对于第三个条件可以向左移动1步指向最后一个最后一个条件即可。在知道了两点之后直接用O(n^3)的复杂度暴力一下就行了了。


#include<iostream>
#include<cstring>
#include<algorithm>

#define MAX 55
using namespace std;

int n,m;
int flag[MAX][5]; //用来存入每个字符串的每种字符需要多少次移动才能得到。 
int min(int a,int b){ return a>b?b:a; }
int Type(char c){ //函数的返回值传入字符的种类,数字,字母,特殊字符。 
	if(c>='0'&&c<='9')
		return 1;
	if(c>='a'&&c<='z')
		return 2;
	return 3;
}
int main()
{
	while(cin>>n>>m){
		for(int i=0;i<n;i++){
			char str[MAX];
			cin>>str;
			flag[i][1]=55,flag[i][2]=55,flag[i][3]=55;
			for(int j=0;j<m;j++){
				int type=Type(str[j]);
				flag[i][type]=min(flag[i][type],min(j,m-j));
//这句表示第i个字符串的第type种字符的需要移动flag[i][type]次才能得到 
			}
		}
		int ans=55*3;
		for(int i=0;i<n;i++){
			for(int j=0;j<n;j++){
				for(int k=0;k<n;k++){
					if(i==j||j==k||k==i)
						continue;
					ans=min(ans,flag[i][1]+flag[j][2]+flag[k][3]);
				}
			}
		}
//然后用三层循环暴力出答案。 
		cout<<ans<<endl;
	}
}

        这个思路是一个暴力代码,虽然是O(n^3)的复杂度,但是,在这个题中的使用倒是很合理。不过我个人感觉这个题的正解应该是用dp,但是,在比赛和链接中貌似没有人是使用dpAC的,大多数都是用暴力过的。可能是因为写的方便的关系吧!不过我自己的做法是一种类似于二分图匹配的做法。虽然最坏复杂度也是O(n^3)。但是,平均呢复杂度比较低。存储的方式是和上面的代码相同的方式。(如果对二分图匹配或者深搜没有什么了解的话就跳过吧!)


#include<iostream>
#include<cstring>
#include<algorithm>

#define MAX 55
using namespace std;

int n,m;
int flag[MAX][5];
int ans_flag[MAX],ans_type[4];
bool vis_type[4];
int min(int a,int b){ return a>b?b:a; }
int abs(int a){ return a>0?a:-a; }
int Type(char c){
	if(c>='0'&&c<='9')
		return 1;
	if(c>='a'&&c<='z')
		return 2;
	return 3;
}
void dfs(int a)
{
	for(int j=1;j<=3;j++){
		if(flag[a][j]!=55&&(ans_type[j]==-1||flag[ans_type[j]][j]>flag[a][j])&&!vis_type[j]){
			vis_type[j]=true;
			if(ans_type[j]==-1){
				ans_type[j]=a;
				return;
			}else{
				ans_type[j]=a;
				dfs(ans_type[j]);
				return;
			}
		}
	}
	return;
}
int graph_math()
{
	memset(ans_type,-1,sizeof(ans_type));
	int res=0;
	for(int j=0;j<n;j++){
		memset(vis_type,false,sizeof(vis_type));
		dfs(j);
	}
	return flag[ans_type[1]][1]+flag[ans_type[2]][2]+flag[ans_type[3]][3];
}
int main()
{
	while(cin>>n>>m){
		for(int i=0;i<n;i++){
			char str[MAX];
			cin>>str;
			flag[i][1]=55,flag[i][2]=55,flag[i][3]=55;
			for(int j=0;j<m;j++){
				int type=Type(str[j]);
				flag[i][type]=min(flag[i][type],min(j,m-j));
			}
		}
		cout<<graph_math()<<endl;
	} 
}


总结:这个题实际上光看给出的这个数据范围本身的正解就是用来暴力的,但是,我总觉得暴力不是正解。算了......只要能AC的就是好方法。暴力出奇迹












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值