1.Spreadsheets
字符串模拟题
题目给出了两种行列位置的表示方法,一个是Excel表示法,一个是(R,C)坐标表示法,我们要做的就是将输入的一种表示转换成另一种表示再输出。
Excel表示法:用A~Z的大写字母表示列,用数字表示行,比如A2表示第2行第1列,AA12表示第12行第27列。
(R,C)坐标表示法:用数字表示行列,比如R2C1表示第2行第1列,R12C27表示第12行第27列。
看完题目就应该想到用26进制(字母)与10进制(数字)互相转换解决问题,然而这里的26进制不同的是A表示1,B表示2…Z表示26,没有用来表示0的字母,需要注意当num%26==0时应该是Z,注意特判。
#include<bits/stdc++.h>
using namespace std;
const char *Const=" ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char s[101];
void Solve1() {
int i=0,j=0,num1=0,num2=0;
int t[101];
for(++i;isdigit(s[i]);++i)
(num2*=10)+=s[i]-'0';
for(++i;s[i];++i)
(num1*=10)+=s[i]-'0';
for(;num1;num1=num1/26-!(num1%26)) { //特判
if(num1%26)
t[++j]=num1%26;
else
t[++j]=26; //特判
}
for(;j;--j)
putchar(Const[t[j]]);
printf("%d\n",num2);
}
void Solve2() {
int i=0,num1=0,num2=0;
for(;isupper(s[i]);++i)
(num2*=26)+=s[i]-'A'+1; //注意这个加一,A表示1而不是0
for(;s[i];++i)
(num1*=10)+=s[i]-'0';
printf("R%dC%d\n",num1,num2);
}
int main() {
int n;
bool flag;
for(scanf("%d",&n);n;--n) {
scanf("%s",s);
flag=0;
for(int i=0;s[i]&&!flag;++i)
if(i&&isdigit(s[i-1])&&isupper(s[i]))
//这里利用了两种表示法的特殊性来判断是哪种表示法,(R,C)表示法在数字后有可能有字母,然而Excel表示法一定不可能
flag=1;
if(flag)
Solve1();
else
Solve2();
}
return 0;
}
2.Shortest path of the king
纯模拟:看国王需要横移和竖移多少步,先把斜移的输出,再输出平移的。总步数就是斜移步数和平移步数的和
#include <cstdio>
#include <algorithm>
using namespace std;
int main()
{
int a,y;
char c,x;
scanf("%c%d\n%c%d",&c,&a,&x,&y);
int t=abs(c-x),k=abs(a-y),n=min(t,k),m=n+abs(t-k);
printf("%d\n",m);//总步数
for(int i=1;i<=n;++i)//斜移
{
if(c<x)putchar('R'),c++;
else putchar('L'),x++;
if(a<y)puts("U"),a++;
else puts("D"),y++;
}
for(int i=n;i<m;++i)//平移
if(a<y)puts("U");
else if(a>y)puts("D");
else if(c<x)puts("R");
else puts("L");
return 0;
}
方法一:切比雪夫距离
切比雪夫距离:两点间x坐标差的绝对值和y坐标差的绝对值的最大值。
国王移动到目标点的步数就是两点间的切比雪夫距离
#include<bits/stdc++.h>
using namespace std;
string s1,s2;
int main()
{
cin>>s1>>s2;
int x1=s1[0]-'a'+1,y1=s1[1]-'0',x2=s2[0]-'a'+1,y2=s2[1]-'0';//计算两个点的坐标
int dis=max(abs(x1-x2),abs(y1-y2));//计算两点的切比雪夫距离
printf("%d\n",dis);
while(dis--)
{
if(x1>x2 && y1>y2){x1--;y1--;printf("LD\n");continue;}//判断一下
if(x1>x2 && y1==y2){x1--;printf("L\n");continue;}
if(x1>x2 && y1<y2){x1--;y1++;printf("LU\n");continue;}
if(x1==x2 && y1>y2){y1--;printf("D\n");continue;}
if(x1==x2 && y1<y2){y1++;printf("U\n");continue;}
if(x1<x2 && y1>y2){x1++;y1--;printf("RD\n");continue;}
if(x1<x2 && y1==y2){x1++;printf("R\n");continue;}
if(x1<x2 && y1<y2){x1++;y1++;printf("RU\n");continue;}
}
}
方法二:贪心
首先读题可以知道国王最多有八个可以移动的方向:L,R,U,D,LU,LD,RU,RD,那么当前位置与终点不同时就要优先走斜线,模拟一下即可知道最短路径的长度为起点与终点横坐标的差的绝对值与纵坐标的差的绝对值中较大的那一个。
由于走斜线的格式均是L或R+U或D,输出移动动作时可以将走斜线分解为横坐标走一步加纵坐标走一步。
#include<bits/stdc++.h>
using namespace std;
char s1[3],s2[3];
int main() {
int x,y;
char cx,cy;
scanf("%s%s",s1,s2);
x=s1[0]-s2[0];
y=s1[1]-s2[1]; //取坐标之差
cx=x<0? 'R':'L';
cy=y<0? 'U':'D'; //根据坐标差的正负选择方向
if(x<0)
x=-x;
if(y<0) //相当于取绝对值
y=-y;
printf("%d\n",x>y? x:y);
for(;x||y;putchar('\n')) { //循环条件,当前点与终点之间有距离
if(x) {
--x;
putchar(cx); //横坐标走一步
}
if(y) {
--y;
putchar(cy); //纵坐标走一步
}
}
return 0;
}
方法三:搜索
宽搜
#include<bits/stdc++.h>
using namespace std;
struct pos{
int x,y,s;
string move[100];
};
queue<pos>q;
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,1,-1,1,-1,1,-1};
string st[8]={"L","R","U","D","LU","LD","RU","RD"};
bool vis[10][10];
int x,y;
int main()
{
string s1,s2;
cin>>s1>>s2;
q.push((pos){s1[0]-'a'+1,s1[1]-'0',0,""});
vis[s1[0]-'a'+1][s1[1]-'0']=1;
x=s2[0]-'a'+1,y=s2[1]-'0';
if(vis[x][y])
{
cout<<0<<endl;
return 0;
}
while(!q.empty())
{
pos u=q.front();
q.pop();
for(int i=0;i<8;i++)
{
pos th;
th.x=u.x+dx[i];
th.y=u.y+dy[i];
th.s=u.s+1;
for(int i=1;i<=u.s;i++)
th.move[i]=u.move[i];
th.move[th.s]=st[i];
if(th.x<1||th.x>8||th.y<1||th.y>8||vis[th.x][th.y])
continue;
vis[th.x][th.y]=1;
if(th.x==x&&th.y==y)
{
cout<<th.s<<endl;
for(int j=1;j<=th.s;j++)
cout<<th.move[j]<<endl;
return 0;
}
q.push(th);
}
}
return 0;
}
深搜(记忆化):用数组记录到每一个点的最小步数
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int qx,qy,zx,zy,c[10][10],p[100],b[100],ans=2147483647;
int fx[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};
void dfs(int x,int y,int z){
if (x==zx&&y==zy){
if (z<ans){
ans=z;
for (int i=1;i<=z;i++)
b[i]=p[i];
}
return;
}
if (c[x][y]<=z) return;
else c[x][y]=z;
for (int i=0;i<8;i++){
int xx=x+fx[i][0];
int yy=y+fx[i][1];
if (xx<1||xx>8||yy<1||yy>8) continue;
p[z+1]=i;
dfs(xx,yy,z+1);
}
}
int main(){
memset(c,0x3f,sizeof(c));
char x;
x=getchar();
qx=x-'a'+1;
scanf("%d",&qy);
x=getchar();
while (x=='\n'||x==' ') x=getchar();
zx=x-'a'+1;
scanf("%d",&zy);
dfs(qx,qy,0);
printf("%d\n",ans);
for (int i=1;i<=ans;i++){
switch(b[i]){
case 0:printf("U\n");break;
case 1:printf("RU\n");break;
case 2:printf("R\n");break;
case 3:printf("RD\n");break;
case 4:printf("D\n");break;
case 5:printf("LD\n");break;
case 6:printf("L\n");break;
case 7:printf("LU\n");break;
}
}
}
3.Before an Exam
方法一:贪心
首先判断sumtime是否在maxtime之和 和 mintime之和之间
如果有解的话就先每天学习mintime[ i ]小时然后多余的时间就依次塞到每一天里,但每一天最多只能塞到那一天的maxtime
#include<bits/stdc++.h>
using namespace std;
int n,i,s,mins,maxs;
int a[31],b[31];//每一天的maxtime和mintime
int main(){
cin>>n>>s;
for(i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
mins+=a[i];//mintime之和
maxs+=b[i];//maxtime之和
}
if(s<=maxs&&s>=mins)//如果有解的话
{
cout<<"YES"<<endl;
s-=mins;
i=1;
while(s) //当s!=0
{
if(s>b[i]-a[i])
{
s-=b[i]-a[i];
a[i]=b[i];
}
else
{
a[i]+=s;
s=0;
}
i++;
}
for(i=1;i<=n;i++)
cout<<a[i]<<' ';
}
else cout<<"NO! YOU ARE DEAD!!!"<<endl;
return 0;
}
方法二:优先队列
首先判断存不存在这么一种方案即总时间不小于最小时间不大于最大时间.
然后首先取每天的最少时间, 如果这样比总时间少的话就从有剩余时间的天里增加时间. 我使用了一个优先队列存每天剩余时间, 从剩余时间最大的那天增加时间.
注意:一天的时间被更新过之后不再放回优先队列
#include<bits/stdc++.h>
using namespace std;
struct Node{
int pos,rest;
bool operator<(const Node& s)const{
return rest>s.rest;
}
};
priority_queue<Node>que;
int n,sum;
int f[36];
int l[35],r[35];
int main(){
scanf("%d%d",&n,&sum);
int maxl,minl;maxl=minl=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&l[i],&r[i]);
maxl+=r[i],minl+=l[i];
}
if(maxl<sum||minl>sum){
printf("NO");
return 0;
}
int ans=0;
for(int i=1;i<=n;++i){
f[i]=l[i],ans+=l[i];
que.push((Node){i,r[i]-l[i]});
}
while(ans<sum){
Node top=que.top();
que.pop();int val=min(sum-ans,top.rest);
f[top.pos]+=val;
ans+=val;
top.rest-=val;
}
printf("YES\n");
for(int i=1;i<=n;++i)
printf("%d ",f[i]);
return 0;
}
…
4.Registration system
方法一:结构体
定义一个结构体包含姓名及拥有此姓名的用户个数,其次边输入边进行判断,如果未找到则输出“OK”并存储,如果找到就看他有几个,进行++后输出
#include<bits/stdc++.h>
using namespace std;
struct name
{
string n;//代表名字
int num;//代表个数
}a[100005];
int main()
{
int jl=0;//记录上一次判断字符串所到达位置,缩短时间
int N;
cin>>N;
for(int i=1;i<=N;i++)
{
string c;cin>>c;
bool flag=0;//标记是否查找到
for(int j=0;j<=jl;j++)
if(a[j].n==c)
{
a[j].num++;//先加再输出
cout<<a[j].n<<a[j].num<<endl;
flag=1;
break;
}
if(!flag)
cout<<"OK"<<endl,a[jl++].n=c;
}
return 0;
}
方法二:map
做这道字符串题需要干什么呢?需要判重, 判断一个字符串有没有出现, 出现了几次。
所以这个问题用map可以很好解决了。首先需要了解一下map的基本操作:
建立 map<string,int>m;, 从字符串映射到整数.
插入 m[str]=key;, str为字符串, key为映射到的整数.
迭代器 map<string,int>::iterator it;, 迭代器相当于是指针(或者说是一种数据类型).
查询字符串是否存在 it=find(str), it为对应元素的迭代器.
通过迭代器获取元素的整数值 int key=it->second, first 是对应的string, second 是对应的字符串.(map中的元素为pair)
这样我们就可以将字符串插入map, 不重复, 每个字符串对应的那个整数就是我们记录这个字符串出现几次的数组的对应下标
用户输入一个字符串,先在map中检索是否存在记录,如果不存在(字符串对应的值为0),则输出"OK"并在map中加入一条以该字符串为索引的记录并赋初值1;如果存在,则输出该字符串本身以及map中该字符串为索引的记录的值,再将字符串为索引的记录的值加一
#include<bits/stdc++.h>
using namespace std; //头文件和命名空间
map<string, long long> mapDatabase; //定义以string为键类型,long long为值类型的map
int main(){
ios::sync_with_stdio(false); //一定意义上的输入输出加速
string sNameInput; //定义字符串,表示用户输入
long long nCount,i; //nCount-输入个数,i-循环变量
cin >> nCount; //读入输入个数
getline(cin, sNameInput); //读取掉输入后留下的不需要的东西
for (i = 1; i <= nCount; ++i){ //循环读取
getline(cin, sNameInput); //读入"用户名"
if (mapDatabase[sNameInput] != 0){ //如果对应值非0,也就是已经有人用这个ID注册过
cout << sNameInput << mapDatabase[sNameInput] << '\n'; //输出原始字符串和这个ID已被注册的次数
++mapDatabase[sNameInput]; //已被注册次数加1
}
else{
cout << "OK\n"; //ID可用
mapDatabase[sNameInput] = 1; //将这个ID的记录添加到map中并且赋初值1
}
}
return 0; //结束
}
#include<bits/stdc++.h>
using namespace std;
map<string,int> m;
int co[100005];//字符串出现几次
int main(){
int n;string str;
scanf("%d",&n);
map<string,int>::iterator it;//迭代器
for(int i=1;i<=n;++i){
cin>>str;it=m.find(str);//是否出现
if(it==m.end()){m[str]=i;printf("OK\n");}
else {
int s=it->second;//在数组co中位置
cout<<str<<++co[s]<<endl;
}
}
return 0;
}