2019年7月12日考试 3题
例题
总结
这次考试差点挂了,1题签到题,2题dfs暴力超出时间,只能打表,3题挂了虽然做过
结果加强数据,那就玄学剪枝+打表。最终WAemmm
跳房子
Time Limit: 1 Sec Memory Limit: 128 MB
Description
奶牛按不太传统的方式玩起小朋友玩的跳房子游戏,现给出一个5*%的由数字组成的网格。它们在格子中向前前跳,向后跳,向左跳,向右跳,跳到网格中另一个数字后,又这样继续跳(可能跳到某个已跳过的数字)。一共在网格中跳过五次后,它们经过的格子数组成一个六位数(可能是0开始头的,例如000201).现问所有可以被跳出来的不同整数的总数。
Input
输入共五行,每行五个数字.
Output
如题
Sample Input
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 2 1
1 1 1 1 1
Sample Output
15
HINT
111111, 111112, 111121, 111211, 111212, 112111, 112121, 121111, 121112,
121211, 121212, 211111, 211121, 212111, and 212121 can be constructed.
No other values are possible.
思路
先双重for+dfs+in+cnt++
不用担心超时问题,但要处理好边界,走过的路径用字符串存下,再用map<string,bool> 映射标记
代码
#include<bits/stdc++.h>
using namespace std;
int n,cnt;
char maze[10][10];
int dir[4][2]={{0,1},{1,0},{-1,0},{0,-1}};
bool in(int x,int y){
return x>=1 && x<=n && y>=1 && y<=n;
}
map<string,bool> vis;
void dfs(int x,int y,int s,string ans){
if(s>6){
if(!vis[ans]){
vis[ans]=1;
cnt++;
}
return ;
}
for(int i=0;i<4;i++){
int tx=x+dir[i][0];
int ty=y+dir[i][1];
if(in(tx,ty)){
dfs(tx,ty,s+1,ans+maze[x][y]);
}
}
}
int main(){
n=5;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>maze[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dfs(i,j,1,"\0");
}
}
while(1);
cout<<cnt;
return 0;
}
排队
Time Limit: 1 Sec Memory Limit: 128 MB
Description
小Q是班长。在校运动会上,小Q班要进行队列表演。小Q要选出2*N名同学编队,每人都被编上一个号,每一个从1到N的自然数都被某2名同学佩戴,现在要求将他们排成一列,使两个编号为1的同学中间恰好夹1名同学,两个编号为2的同学中间恰好夹2名同学,……,两个编号为N的同学中间恰好夹N名同学,小Q希望知道这样的排法能否实现。
Input
输入文件仅包括一行,即要处理的N。N<=13
Output
输出有多少种排列顺序.
Sample Input
3
Sample Output
2
思路
本人太蒟无法写出13和12能A的DFS,那只能打表…
dfs枚举数字1~n,for枚举格子,开个数组i+s+1 和i (s是数值),这样就可以保证s中有s个人
但有一个可行性剪枝方案
设问题的一个可行解为a1,a2,……,an,其中ai为标号为i的数字的位置,
这些数字它们对应数字的位置应该为a1+1+1,a2+2+1,……,an+n+1.这2N个整数a1,a2,……,an, a1+1+1,a2+2+1,……,an+n+1正是整数1,2,3,……,2N,因而
a1+a2+…+an+(a1+1+1)+(a2+2+1)+…+(an+n+1)=
2(a1+a2+an)+n(n+1)/2+n=2n(2n+1)/2
2(a1+a2+…+an)=(3n2-n)/2
4(a1+a2+…+an)=n(3n-1)
可见n(3n-1)应该为4的倍数,当n mod 4=0,1,2,3时,n(3n-1) mod 4分别为0,2,2,0,故n mod 4=1或2时,问题无解
代码
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
int n,cnt,a[50];
void dfs(int s){
if(s>n){
cnt++;
return;
}
for(int i=1;i+s+1<=2*n;i++){
if(!a[i] && !a[i+s+1]){
a[i]=s;
a[i+s+1]=s;
// cout<<cnt<<endl;
// for(int i=1;i<=2*n;i++){
// cout<<a[i]<<" ";
// }
// cout<<endl;
// Sleep(2000);
dfs(s+1);
a[i]=0;
a[i+s+1]=0;
}
}
// cout<<cnt<<endl;
// for(int i=1;i<=2*n;i++){
// cout<<a[i]<<" ";
// }
// cout<<endl;
// Sleep(1000);
}
int main(){
cin>>n;
if(n mod 4=1 || n mod 4=2){
cout<<0;
return 0;
}
dfs(1);
cout<<cnt;
return 0;
}
Unit Fraction Partition
Time Limit: 1 Sec Memory Limit: 128 MB
Description
给出数字P,Q,A,N,代表将分数P/Q分解成至多N个分数之和,这些分数的分子全为1,且分母的乘积不超过A。例如当输入数据为2 3 120 3时,我们可以得到以下几种分法:
Input
本题含有多组测试数据,每组给出四个数P,Q,A,N,其中 p,q <= 800, A <= 12000,N <= 7.当输入的四个数均为0时,代表测试结束.
Output
针对每组数据,输出共有多少种不同的分法。
Sample Input
2 3 120 3
2 3 300 3
2 3 299 3
2 3 12 3
2 3 12000 7
54 795 12000 7
2 3 300 1
2 1 200 5
2 4 54 2
0 0 0 0
Sample Output
4
7
6
2
42
1
0
9
3
思路
老师讲过的题本蒟蒻居然wa了emmm
暴力枚举每个分母
a/b+c/d=ac+bc/bd(两个分数向加,分子分母公式)
ab=dc(两个分数相等,分子分母公式)
再加些极大化,可行性剪枝
代码
#include<bits/stdc++.h>
using namespace std;
int a,cnt;
void dfs(int p,int q,int nex,int x,int t){
if(nex<=a && !p){
cnt++;
return;
}
if(nex*x>a){
return;
}
if(!t){
return;
}
if(p*x>q*t){
return;
}
for(int i=x;i<=a;i++){
if(nex*i>a){
return;
}
int tx=p*i-q;
if(tx>=0){
dfs(tx,q*i,nex*i,i,t-1);
}
}
}
int main(){
int p,q,n;
while(1);
while(cin>>p>>q>>a>>n && p!=0 && q!=0 && a!=0 && n!=0){
cnt=0;
dfs(p,q,1,1,n);
cout<<cnt<<endl;
}
return 0;
}