冬令营 Winter Camp搜索专题

Posted ZSYL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了冬令营 Winter Camp搜索专题相关的知识,希望对你有一定的参考价值。

【冬令营 Winter Camp】搜索专题

A - 棋盘问题

在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别。要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放方案C。

Sample Input

2 1
#.
.#
4 4
...#
..#.
.#..
#...
-1 -1
2
1

思路:深度优先遍历,一行一行判断能否放棋子,每一行需要判断每一列能否放能放,能放/不能放也都递归到下一行(这样能包含所有放棋子的情况),注意回溯。

Java

import java.util.Scanner;

public class Main 
    static int n, k, cnt;
    static char[][] array;
    static boolean[] used;
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()) 
            n = sc.nextInt();
            k = sc.nextInt();
            if (n == -1 && k == -1)
                break;
            cnt = 0;
            array = new char[n][n];
            used = new boolean[n];
            sc.nextLine();
            for (int i = 0; i < n; i++) 
                array[i] = sc.nextLine().toCharArray();
            
            dfs(0, 0);
            System.out.println(cnt);
        
    
    public static void dfs(int i, int sum) 
        if (i == n) 
            if (sum == k) 
                cnt++;
            
            return;
        
        for (int j = 0; j < n; j++) 
            if (array[i][j] == '.')
                continue;
            if (!used[j]) 
                used[j] = true;
                dfs(i+1, sum+1);
                used[j] = false;
            
        
		dfs(i+1, sum);
    

C++

#include<iostream>
#include<string.h>
using namespace std;

int n, k, cnt;
char a[10][10];
bool flag[10];

void dfs(int x, int sum) 
    if (x == n) 
        if (sum == k)
            cnt++;
        return;
    
    // 遍历一行的每一列,判断能否放棋子
    for (int i = 0; i < n; i++) 
        if (a[x][i] == '.' || flag[i])  // 如果当前x,i位置为.或者是所在行列已经被占用则跳过
            continue;
        flag[i] = true;  // 修改标记数组
        dfs(x+1, sum+1);  // 放一枚棋子递归下一行
        flag[i] = false;  // 回溯
    
    // 这一行不放棋子,跳过(模拟所有)
    dfs(x+1, sum);

int main() 
    while (1) 
        cin >> n >> k;

        if (n == -1 && k == -1)
            break;
        
        // 每次测试都需要修改全局变量的初始值
        memset(flag, false, sizeof(flag)); 
        for (int i = 0; i < n; i++) 
            for (int j = 0; j < n; j++) 
                cin >> a[i][j];
            
        
        cnt = 0;
        dfs(0, 0);
        printf("%d\\n", cnt);
    
    return 0;

B - Perket

你有 N 种配料,每种配料有酸度 S 和苦度 B 。用这些配料做成Perket时,总的酸度为所有配料酸度的乘积,总的苦度是所有配料苦度的和。你至少需要添加一种配料。

为了使口感适中,总的酸度和苦度之差的绝对值应该尽可能小,求这个最小值。

4
1 7
2 6
3 8
4 9
1

Java

import java.util.Scanner;

public class Main 
    static int n, k, cnt;
    static int[][] array;
    static boolean[] used;
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        array = new int[n][2];
        cnt = Integer.MAX_VALUE;
        for (int i = 0; i < n; i++) 
            array[i][0] = sc.nextInt();
            array[i][1] = sc.nextInt();
        
        dfs(0, 1, 0, 0);
        System.out.println(cnt);
    
    public static void dfs(int i, int a, int b, int k) 
        if (i == n) 
            if (k > 0)
                cnt = Math.min(cnt, Math.abs(a - b));
            return;
        
        dfs(i+1, a*array[i][0], b + array[i][1], k+1);
        dfs(i+1, a, b, k);
    

C++

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1E5 + 7;
ll current_exception = 1e9+10;
ll arr[10][2];
ll n, k, cnt = 1e9+1;

void dfs(ll i, ll a, ll b) 
    if (i == n) 
        if (k > 0)
            cnt = min(cnt, abs(a - b));
        return;
    
    k++;
    dfs (i + 1, a * arr[i][0], b + arr[i][1]);
    k--;
    dfs(i + 1, a, b);

int main()

    cin >> n;
    for (int i = 0; i < n; i++) 
        cin >> arr[i][0] >> arr[i][1];
    
    dfs(0, 1, 0);
    cout << cnt;

思路:n<=10,数据较小,暴力求解,每一个都试试加入和不加入两种情况,取最小值,来源大佬博客

#include<iostream>
#include<cmath>
#include<string.h>
#include<algorithm>
#include<map>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=200100;
const int INF=pow(2,31)-1;
const int maxm=5e4+5;
const int mod=1000000007;
ll n;
ll s[maxn],b[maxn];
ll ans,cnt;
ll mi=1e9+10;
/*bool judge(ll x)
    for(int i=1;i<=n;i++)

    
*/
void dfs(ll step,ll k)
    if(step==n+1)
        if(k>=1)mi=min(mi,abs(ans-cnt));
        return ;
    
    ans*=s[step];
    cnt+=b[step];
    dfs(step+1,k+1);
    cnt-=b[step];
    ans/=s[step];
    dfs(step+1,k);
    return ;

int main()
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>s[i]>>b[i];
    
    ans=1;
    dfs(1,0);
    cout<<mi<<endl;
    return 0;

C - 全排列

给定一个由不同的小写字母组成的字符串,输出这个字符串的所有全排列。我们假设对于小写字母有’a’< ‘b’< …<‘y’<‘z’,而且给定的字符串中的字母已经按照从小到大的顺序排列。

输入格式

输入只有一行,是一个由不同的小写字母组成的字符串,已知字符串的长度在1到6之间。

输出格式

输出这个字符串的所有排列方式,每行一个排列。要求字母序比较小的排列在前面。

abc
abc
acb
bac
bca
cab
cba

Java

参考洛谷 P1706 全排列问题(Java版)

import java.util.Scanner;

public class Main 
    static int n, k, cnt;
    static int[][] array;
    static char[] arr;
    static boolean[] used;
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
        arr = sc.nextLine().toCharArray();
        used = new boolean[arr.length];
        Arrays.sort(arr);
        fullSort(new StringBuilder());
    
    public static void fullSort(StringBuilder res) 
        if (res.length() == arr.length) 
            System.out.println(res.toString());
            return;
        
        for (int i = 0; i < arr.length; i++) 
            if (!used[i]) 
                used[i] = true;
                res.append(arr[i]);
                fullSort(res);
                res.deleteCharAt(res.length()-1);
                used[i] = false;
            
        
    

C++

#include<iostream>
#include<cmath>
#include<string.h>  // strlen()
#include<algorithm>  // 排序操作
#include<map>
using namespace std;
typedef long long int ll;
typedef pair<ll,ll> P;
const int maxn=200100;
const int INF=pow(2,31)-1;
const int maxm=5e4+5;
const int mod=1000000007;
char str[maxn],st[maxn];  // 字符数组
ll cnt;
ll used[maxn];
ll n;
void dfs(ll step)
    // 输出结果
    if(step==n+1)
        for(int i=1;i<=cnt;i++)
            cout<<st[i];
        
        cout<<endl;
        return ;
    
    for(int i=1;i<=n;i++)
        if(!used[i])
            used[i]=1;
            st[++cnt]=str[i];
            dfs(step+1);
            used[i]=0;
            cnt--;
        
    
    return ;

int main()
    cin>>(str+1);
    n=strlen(str+1);
    sort(str+1,str+1+n);
    dfs(1);
    return 0;

D - 自然数拆分

对于任意大于 1 的自然数 n,总是可以拆分成若干个小于 n 的自然数之和。

现请你编写程序求出 n 的所有拆分。

5
5=1+1+1+1+1
5=1+1+1+2
5=1+1+3
5=1+2+2
5=以上是关于冬令营 Winter Camp搜索专题的主要内容,如果未能解决你的问题,请参考以下文章

冬令营 Winter Camp数学专题

冬令营Winter Camp字符串专题(Triple语言版)

JSZX Winter Camp Day 3 爆零记

2019 wannafly winter camp

Winter Camp 2016游记

KTU Programming Camp (Winter Training Day 1)