题目难度由低到高
1.错误的票据
来源:第四届蓝桥杯省赛C++A/B组
题目链接
题解:找出最大和最小的数,同时再用一个数组记录每个数字的个数,最后遍历一遍即可
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=10010,M=100010;
int cnt[M];
int main(){
int line,i=0,Min=100001,Max=0,a;
int n,m; //m表示断号ID,n表示重号ID
cin>>line;
while(line--){
while(cin>>a){
cnt[a]++;
Max=max(Max,a);
Min=min(Min,a);
}
}
for(int j=Min;j<Max;j++){
if(cnt[j]==0) m=j;
else if(cnt[j]==2) n=j;
}
cout<<m<<" "<<n<<endl;
return 0;
}
java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static int N = 1000010;
static boolean[] f = new boolean[N];
static int cid ;
static int did ;
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(reader.readLine().trim());
int maxv = Integer.MIN_VALUE;
int minv = Integer.MAX_VALUE;
while(n -- > 0)
{
String[] s1 = reader.readLine().split(" ");
for(int i = 0;i < s1.length;i++)
{
int t = Integer.parseInt(s1[i]);
maxv = Math.max(maxv, t);
minv = Math.min(minv, t);
if(f[t]) cid = t;
f[t] = true;
}
}
for(int i = minv ;i <= maxv ;i ++)
{
if(!f[i])
{
did = i;
break;
}
}
System.out.println(did + " " + cid);
}
}
2. 全球变暖
来源:第九届蓝桥杯省赛C++A/B组
题目链接
题解:我们通过dfs查询每一个岛屿,如果这个岛屿不会沉,就记录下来,然后用dfs查询到的总岛屿减去不会沉的岛屿即可;
c++代码:
#include <iostream>
#include <iomanip>
#include <string>
#include <string.h>
using namespace std;
const int N = 1100;
char maps[N][N];
bool biao[N][N];
int ways[4][2] = {
{
1, 0}, {
0, 1}, {
-1, 0}, {
0, -1}}; //上下左右
int ans;
int v;
void dfs(int x, int y)
{
biao[x][y] = false;
if (maps[x + 1][y] == '#' && maps[x - 1][y] == '#' && maps[x][y + 1] == '#' && maps[x][y - 1] == '#' && v == 1) //用v作标记,因为一个岛屿可能有多个满足要求的点
{
ans++;
v = 0; //这里不能直接退出函数,dfs必须把所有点都标记完,不然以后查找会出现重复
}
for (int i = 0; i <= 3; i++)
{
int nx = x + ways[i][0];
int ny = y + ways[i][1];
if (maps[nx][ny] == '#' && biao[nx][ny]) //满足条件继续搜索
dfs(nx, ny);
}
}
int main()
{
int n;
cin >> n;
memset(biao, true, sizeof biao);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
cin >> maps[i][j];
}
int yjl = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
if (maps[i][j] == '#' && biao[i][j])
{
v = 1;
yjl++;
dfs(i, j);
}
}
cout << yjl - ans << endl; //总岛数减去不会沉的
}
java代码:
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class Main{
static int N = 1010;
static int n;
static char[][] g = new char[N][N];
static boolean[][] st = new boolean[N][N];
static int[] dx = new int[] {
-1,0,1,0};
static int[] dy = new int[] {
0,1,0,-1};
static boolean bfs(int x,int y)
{
Queue<PIIs> q = new LinkedList<PIIs>();
q.add(new PIIs(x,y));
st[x][y] = true;
int total = 0;//当前位置连通陆地的数量
int bound = 0;//被淹没陆地的数量
while(!q.isEmpty())
{
PIIs t = q.poll();
total ++;
boolean is_bound = false;//判断岛屿是否被淹没
for(int i = 0;i < 4;i++)
{
int a = t.x + dx[i];
int b = t.y + dy[i];
if(a < 0 || a >= n || b < 0 || b >= n) continue;
if(st[a][b]) continue;
if(g[a][b] == '.')
{
is_bound = true;
continue;
}
q.add(new PIIs(a,b));
st[a][b] = true;
}
if(is_bound) bound ++;
}
return total == bound;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
for(int i = 0;i < n;i++)
{
char[] charArray = scan.next().toCharArray();
for(int j = 0;j < n;j++)
{
g[i][j] = charArray[j];
}
}
int cnt = 0;
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++)
{
if(!st[i][j] && g[i][j] == '#')
{
if(bfs(i,j)) cnt ++;
}
}
}
System.out.println(cnt);
}
}
class PIIs
{
public int x;
public int y;
public PIIs(int x,int y)
{
this.x = x;
this.y = y;
}
}
3.波动数列
来源:第五届蓝桥杯省赛C++A组
题目链接
题解:这题如果数字小一点可以通过dfs直接搜索,可是如此大的数字很明显是不行的;
我们设首相为t,F(i)={a,-b},第一个数t,第二个数t+F(1),第三个数t+F(1)+F(2)…,然后我们对这些数做和,可得到
nt + (n-1)F(1) + (n-2)F(2) + … +F(n-1) =s ,在变形一下,nt = s - {(n-1)F(1) + (n-2)F(2) + … +F(n-1)},那么只要右边的能整除n就满足条件(因为首项t是不确定的);然后我们发现(n-1)+(n-2)+…+1 在n确定时是个定值,也就是a和-b的总数是一定的,那么我们知道a的数目,就可以知道b的数目,也就能判断是否满足条件,现在我们只要求方案数即可,我们把(n-1)F(1)看做一个大小为n-1的货,其他依次类比,这就转化为了01背包求方案数的问题。
c++代码:
#include<iostream>
using namespace std;
#define MOD 100000007
#define MAXN 1100
long long n,s,a,b;
long long all;
long long Bo[MAXN*MAXN];
void fun_dp()//求方案数
{
long long i,j;
Bo[0]=1;//什么都没有是一种方案
for(i=1;i<n;i++)//枚举货物,假设货物全部为a
{
for(j=i*(i+1)/2;j>=0;j--)//(j代表a的个数)(i*(i+1)/2 代表有大小为i的货物时最大的体积,我们把(n-1)F(1) + (n-2)F(2) + ....... +F(n-1)放过来看了
{
if(i<=j )
{
Bo[j] = (Bo[j] + Bo[j-i]) % MOD;//求a为j时的方案数,为j时是满足的,j-i 然后把此时的货物放进去也是满足的
}else{
Bo[j] = Bo[j]; //放不进去
}
}
}
}
int fun_sum()
{
long long count=0,i;
long long temp;
for(i=0;i<=all;i++)
{
temp = s - i*a + (all - i)*b;//满足条件
if(temp%n == 0)
{
count = (count+Bo[i])%MOD;
}
}
return count;
}
int main()
{
long long count;
cin >> n >> s >> a >> b;
all = n*(n-1)/2; //最多可以增加多少个a(背包容量最大值)
fun_dp();//进行动态规划的函数
count = fun_sum();//统计总数
cout << count;
return 0;
}
java代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static final int mod=100000007;
static long n,s,a,b;
static long all;
static long Bo[]=new long[1100*1100];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
n=sc.nextLong();
s=sc.nextLong();
a=sc.nextLong();
b=sc.nextLong();
all = n*(n-1)/2; //最多可以增加多少个a(背包容量最大值)
long count;
fun_dp();//进行动态规划的函数
count = fun_sum();//统计总数
System.out.println(count);
}
static void fun_dp()//求方案数
{
int i,j;
Bo[0]=1;//什么都没有是一种方案
for(i=1;i<n;i++)//枚举货物,假设货物全部为a
{
for(j=i*(i+1)/2;j>=0;j--)//(j代表a的个数)(i*(i+1)/2 代表有大小为i的货物时最大的体积,我们把(n-1)F(1) + (n-2)F(2) + ....... +F(n-1)放过来看了
{
if(i<=j )
{
Bo[j] = (Bo[j] + Bo[j-i]) % mod;//求a为j时的方案数,为j时是满足的,j-i 然后把此时的货物放进去也是满足的
}else{
Bo[j] = Bo[j]; //放不进去
}
}
}
}
static long fun_sum()
{
long count=0;
long temp;
int i;
for(i=0;i<=all;i++)
{
temp = s - i*a + (all - i)*b;//满足条件
if(temp%n == 0)
{
count = (count+Bo[i])%mod;
}
}
return count;
}
}
4.糖果
来源:第十届蓝桥杯省赛C++A组
题目链接
题解:最多只有20种口味,那么很明显是状态压缩dp了,我们开一个(1<<20)大小的数组用于储存每一种状态,剩下的就是类似背包来找最佳组合了;
c++代码:
#include <iostream>
using namespace std;
const int N = 1 << 20 + 5;
int dp[N], package[N];
int main()
{
int n, k, m;
cin >> n >> m >> k;
int a;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
{
cin >> a;
package[i] |= 1 << (a - 1); //因为一开始已经有一位了,故只需要移动a-1位
}
dp[package[i]] = 1; //每一包都是一个状态,故存在的状态初始为1
}
for (int i = 1; i <= n; i++) //01背包?
for (int j = 1; j < (1 << m); j++) //枚举每一个状态
{
if (dp[j] == 0) //说明暂时还没有存在这种状态
continue;
if (dp[j | package[i]] == 0 || dp[j] + 1 < dp[j | package[i]]) //能通过第i包糖引出一个新的状态,或优化一个存在的状态
dp[j | package[i]] = dp[j] + 1;
}
if (dp[(1 << m) - 1] == 0)
cout << "-1" << endl;
else
{
cout << dp[(1 << m) - 1] << endl;
}
}
java代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static final int N=1<<20+5;
static int dp[]=new int[N];
static int packages[]=new int[105];
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n,k,m;
n=sc.nextInt();
m=sc.nextInt();
k=sc.nextInt();
int a;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= k; j++)
{
a=sc.nextInt();
packages[i] |= 1 << (a - 1);//因为一开始已经有一位了,故只需要移动a-1位
}
dp[packages[i]] = 1; //每一包都是一个状态,故存在的状态初始为1
}
for (int i = 1; i <= n; i++) //01背包?
for (int j = 1; j < (1 << m); j++) //枚举每一个状态
{
if (dp[j] == 0) //说明暂时还没有存在这种状态
continue;
if (dp[j | packages[i]] == 0 || dp[j] + 1 < dp[j | packages[i]]) //能通过第i包糖引出一个新的状态,或优化一个存在的状态
dp[j | packages[i]] = dp[j] + 1;
}
if (dp[(1 << m) - 1] == 0)
System.out.println("-1");
else
{
System.out.println(dp[(1 << m) - 1]);
}
}
}