Day1

搜索

  • 深度优先搜索
    •     事实上,深度优先搜索属于图算法的一种,英文缩写为DFS即 Depth First Search。其过程简要来说是对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.
          举例说明之:下图是一个无向图,如果我们从A点发起深度优先搜索(以下的访问次序并不是唯一的,第二个点既可以是B也可以是C,D),则我们可能得到如下的一个访问过程:A->B->E(没有路了!回溯到A)->C->F->H->G->D(没有路,最终回溯到A,A也没有未访问的相邻节点,本次搜索结束).
          简要说明深度优先搜索的特点:每次深度优先搜索的结果必然是图的一个连通分量.深度优先搜索可以从多点发起.如果将每个节点在深度优先搜索过程中的"结束时间"排序(具体做法是创建一个list,然后在每个节点的相邻节点都已被访问的情况下,将该节点加入list结尾,然后逆转整个链表),则我们可以得到所谓的"拓扑排序",即topological sort
  • 广度优先搜索

八皇后

题目描述

一个如下的\(6*6\)的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行、每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子。

![八皇后][1]

上面的布局可以用序列\(2 4 6 1 3 5\)来描述,第\(i\)个数字表示在第&i&行的相应位置有一个棋子,如下:

行号 \(1 2 3 4 5 6\)

列号 \(2 4 6 1 3 5\)

这只是棋子放置的一个解。请编一个程序找出所有棋子放置的解。
并把它们以上面的序列方法输出,解按字典顺序排列。
请输出前 3 个解。最后一行是解的总个数。

输入格式

一行一个正整数 n,表示棋盘是 n×n 大小的。

输出格式

前三行为前三个解,每个解的两个数字之间用一个空格隔开。第四行只有一个数字,表示解的总数。

输入

6

输出

2 4 6 1 3 5
3 6 2 5 1 4
4 1 5 2 6 3
4

说明/提示

【数据范围】
对于\(100%\)的数据,6 \le n \le 136≤n≤13。

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int a[25];
int n, ans=0;
bool vis[25];
void dfs(int x) 
{
	if(x==n+1)
	{
		ans++;
		if(ans<=3)
		{
			for(int i=1; i<=n; i++) printf("%d ", a[i]);
			putchar('\n');
		}
		return ;
	}
	for(int i=1; i<=n; i++)
	{
		if(vis[i]==1) continue;
		bool ok=1;
		for(int j=1; j<x; j++)
		{
			if(abs(x-j)==abs(i-a[j]))
			{
				ok=0;
				break;
			}
		}
		if(ok)
		{
			a[x]=i;
			vis[i]=1;
			dfs(x+1);
			vis[i]=0;
		}
	}
	return ;
}
int main()
{
	scanf("%d", &n);
	dfs(1);
	printf("%d ", ans);
	return 0;
}

八数码

题目描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入格式

输入初始状态,一行九个数字,空格用0表示

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

输入

283104765

输出

4
#include <cstdio>
#include<map>
#include<queue>
#include<algorithm>
#define ll long long
using namespace std;
const ll dx[]={-1,0,0,1}, dy[]={0,-1,1,0};
ll n;
bool check(int nx, int ny)
{
    return(nx<0||ny<0||nx>2||ny>2);
}
int main()
{
    scanf("%lld", &n);
    queue<ll> q;
    q.push(n);
    map<ll, ll> m;
    m[n] = 0;
    while(!q.empty())
    {
        int u = q.front(); 
        int c[3][2], f=0, g=0, n=u; q.pop();
        if(u == 123804765) break;
        for(ll i=2; i>=0; i--)
        {
            for(ll j=2; j>=0; j--)
            {
                c[i][j] = n%10, n/=10;
                if(!c[i][j]) f=i, g=j;
            }
        }//状态转移
        for(ll i=0; i<4; i++)//移动
        {
            ll nx=f+dx[i], ny=g+dy[i], ns=0;
            if(check(nx, ny)) continue; 
            swap(c[nx][ny], c[f][g]);
            for(ll i=0; i<3; i++)
            {
                for(ll j=0; j<3; j++) ns = ns*10+c[i][j];
                {
                    if(!m.count(ns))
                    {
                        m[ns] = m[u]+1;
                        q.push(ns);
                    }
                    swap(c[nx][ny], c[f][g]);
                }
            }
        }
    }
    printf("%d", m[123804765]);
    return 0;
}

生日蛋糕

题目背景

7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层

生日蛋糕,每层都是一个圆柱体。

设从下往上数第i(1<=i<=M)层蛋糕是半径为\(R_i\),高度为\(H_i\)的圆柱。当i<M时,要求\(R_i>R_{i+1}\)\(H_i>H_{i+1}\)
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
\(Q= Sπ\)
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。

(除Q外,以上所有数据皆为正整数)

题目描述

![生日蛋糕][3]

输入格式

有两行,第一行为N(N<=20000),表示待制作的蛋糕的体积为Nπ;第二行为M(M<=15),表示蛋糕的层数为M。

输出格式

仅一行,是一个正整数S(若无解则S=0)。

输入

100
2

输出

68
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int a[21], b[21], m, n, ans; 
void search(int v, int s, int p, int r, int h)
{
    int hh;
    if (p == 0)
    {
    	if (v==n && s<ans)//判断是否符合要求并得到更优解
            ans = s;//更新
        return ;
    }
    if(v+b[p-1] > n) return ;//体积超出 
    if(s+a[p-1] > ans) return ;//表面积超出 
    if(2*(n-v)/r+s >= ans)  return; //当前的表面积+余下的侧面积>当前最优值
       	 							//剩余表面积FS>=2*V剩/r   
        							//若FS+s>=ans 则不符合 
    for(int i=r-1; i>=p; i--)//枚举上一层的半径
    {
        if(p == m) s = i*i;
        hh = min((n-v-b[p-1])/(i*i),h-1);
        for(int j=hh; j>=p; j--)//枚举上一层的高
        search(v+i*i*j, s+2*i*j, p-1, i, j);
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    ans = 2147483647;
    a[0] = b[0] = 0;
    for(int i = 1; i<21; i++)
    {
		a[i] = a[i-1]+2*i*i;//第i层使用的最大表面积 
        b[i] = b[i-1]+i*i*i;//第i层使用的最大体积 
    }
    search(0, 0, m, n+1, n+1);
    if(ans == 2147483647) printf("0");
    else printf("%d", ans);
    return 0;
}
  • 上面大部分是搜索,当然还有剪枝
posted @ 2020-01-16 11:53  orange_lyc  阅读(121)  评论(0编辑  收藏  举报