6/23~6/24
作者:互联网
1.除法uva725
题面:输入正整数n,按从小到大顺序输出所有形如abcde/fghij=n的表达式,其中aj恰好为09的一个排列,可以有前导零
注意点:
-
前导零只可能出现在除数中,即被除数为和除数最多为五位数
-
通过对除数进行dfs枚举,并记录该枚举方案是否有前导零,计算得到被除数,再检验每一个数字是否存在即可
#include<bits/stdc++.h>
using namespace std;
int n;
bool vis[10],flag;
int v[10];
int check(int a,int b){
memset(v,0,sizeof v);
int m;
if(((a / 100000) > 0) || ((b / 100000) > 0))return 0;
while(a){
m = a % 10;
a /= 10;
v[m] += 1;
}
while(b){
m = b % 10;
b /= 10;
v[m] += 1;
}
if(v[0] > 1)return 0;
for(int i = 1; i <= 9; i++){
if(v[i] != 1)return 0;
}
if(v[0] == 0)return 2;
return 1;
}
void dfs(int cnt,int tot,int now){
if(cnt >= tot){
int m = n * now;
if(check(m,now)){
if(check(m,now) == 1)printf("%d / %d = %d\n",m,now,n);
else printf("%d / 0%d = %d\n",m,now,n);
flag = 1;
}
return;
}
for(int i = 0; i <= 9; i++){
if(cnt == 0 && i == 0)continue;
if(!vis[i]){
now *= 10;
now += i;
vis[i] = 1;
dfs(cnt + 1,tot,now);
vis[i] = 0;
now /= 10;
}
}
}
int main(){
int cnt = 1;
while(cin >> n){
if(n == 0){
break;
}
if(cnt != 1)puts("");
flag = 0;
for(int i = 1; i <= 5; i++){
dfs(0,i,0);
}
cnt++;
if(!flag)printf("There are no solutions for %d.\n",n);
}
}
2.分数拆分uva10976
题面:输入正整数k,找到所有正整数x >= y,使1/k = 1/x + 1/y
- 初看此题,容易直接将分数运算转换为浮点运算,然而限于精度等问题,这种思路是行不通的,因此,可以尝试通过枚举x或y与k通分进行运算,并检查是否符合题意即可
- 枚举x还是y?由关系式可以得到,2y<=k,因此y的范围可以很好确定,然而x不好确定其上界,因此选择y进行枚举
- 进行检验时,只需要检查一下算出的分数是否可以化简成1/x的形式即可,这里采用辗转相除法来计算最大公倍数
#include<bits/stdc++.h>
using namespace std;
int k;
const int MAXN = 10000;
int find(int a,int b){
if(b == 0){
return a;
}
int c = a % b;
return find(b,c);
}
int get(int a,int b){
int s = find(a,b);
int num = (a / s) * (b / s) * s;
return num;
}
struct item{
int k,x,y;
}w[MAXN];
int main(){
freopen("B.out","w",stdout);
while(cin >> k){
int cnt = 0;
for(int y = k + 1; y <= 2 * k; y++){
int s = get(y,k);
int a = s / k;
int b = s / y;
int m = a - b;
if(s % m == 0){
s /= m;
cnt++;
w[cnt].k = k;
w[cnt].x = s;
w[cnt].y = y;
}
}
cout << cnt << endl;
for(int i = 1; i <= cnt; i++){
printf("1/%d = 1/%d + 1/%d\n",w[i].k,w[i].x,w[i].y);
}
}
}
3.邮票面值设计洛谷p1021
如题:给定一个信封,最多只允许粘贴 N 张邮票,计算在给定 K(N+K≤15)种邮票的情况下(假定所有的邮票数量都足够),如何设计邮票的面值,能得到最大值 MAX,使在 1 至 MAX 之间的每一个邮资值都能得到。
破题:设计邮票的面值 = 枚举邮票的面值 确定MAX = 根据所枚举出来的邮票来计算所能取到的最大的值
- 一个小细节:既然要求能够满足1—MAX之间的组合,这就意味着1必将是所取的邮票面值的一个
- 枚举的上界如何确定?这也是此题的一个难点之一,确定好了就过,否则TLE。
由于要求可以组合成的面额必须连续,因此,如果本次枚举的面额过于大,则必然不能连续。易知,若面额max > n + 1,则无法构成连续组合!,因此,枚举的上界得以确定,该题结束一半。 - 确定MAX,自然想到通过动态规划来确定每种面额至少需要多少张邮票来组成(面额最大为n*(n + 1)),若张数大于最多的个数,则无法做到连续。(完)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int dp[MAXN],m,n,k,ans,mon[20],an[20];
int cal(int x){
int ma = 0;
ma = n * x;
memset(dp,0x3f,sizeof dp);
dp[0] = 0;
for(int i = 1; i <= k; i++){
for(int j = mon[i]; j <= ma; j++){
dp[j] = min(dp[j],dp[j - mon[i]] + 1);
}
}
for(int i = 1; i <= ma; i++){
if(dp[i] > n)return i - 1;
}
return ma;
}
void dfs(int cnt,int last,int last1){
if(cnt > k){
int sum = cal(mon[k]);
// cout << last << "**" << sum << endl;
// for(int i = 1; i <= k; i++){
// cout << mon[i] << " ";
// }
// puts("");
if(ans < sum){
ans = sum;
for(int i = 1; i <= k; i++){
an[i] = mon[i];
}
}
return;
}
for(int i = last + 1; i <= last1 + 1; i++){
mon[cnt] = i;
int x = cal(i);
dfs(cnt + 1,i,x);
mon[cnt] = 0;
}
}
int main(){
cin >> n >> k;
m = (n + 1) * n;
mon[1] = 1;
dfs(2,1,n);
for(int i = 1; i <= k; i++){
cout << an[i] << " ";
}
puts("");
printf("MAX=%d\n",ans);
}
4.洛谷p1118
- 杨辉三角加dfs,较轻松
标签:24,邮票,return,23,int,枚举,now,10 来源: https://www.cnblogs.com/CZ-9/p/16410394.html