[题解] 跳房子 排队 Unit Fraction Partition 2019年7月12日考试 3题 C++

例题

总结

这次考试差点挂了,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;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值