您的位置:首页 > 其它

SCUT ACM PLACTICE # 3 二进制枚举,深搜,广搜

2017-01-24 13:30 253 查看
Links:https://vjudge.net/contest/145674#overview

A - 搜索 初心者向 HDU - 2553

简单搜索n皇后,主要是要处理判断是否能放置的问题。

这次我用了四个数组来判断行,列,主对角和副对角是否已经有棋子。

#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdio.h>
using namespace std;
int n;
bool h[50], l[50], z[50], f[50];
int ans[15];

int dfs(int x, int y){

if (y == n){ return 1; }
int ans = 0;
h[x] = 1, l[y] = 1, z[x + y] = 1, f[x - y + 20] = 1;
for (int i = 1; i <= n; i++){
if (h[i] == 0 && l[y + 1] == 0 && z[i + y + 1] == 0 && f[i - y - 1 + 20] == 0){
ans += dfs(i, y + 1);
}
}
h[x] = 0, l[y] = 0, z[x + y] = 0, f[x - y + 20] = 0;

return ans;
}

int main(){
for (int i = 1; i <= 10; i++){
for (int j = 1; j <= i; j++){
n = i;
ans[i] += dfs(j, 1);
}
}
while (~scanf("%d", &n),n!=0){
printf("%d\n", ans
);
}
return 0;
}


B - 搜索 中级者向 POJ - 3278

广搜,能够对当前数字+1,-1,*2,求最小步骤从初始数字到终末数字。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<queue>
using namespace std;
int fx, fy;
int astep;
int v[300005];
struct point{
int x;
int s;
}beg;
queue<point> que;
int bfs(){
int ans = -1;
int k = fy > fx ? (fy - fx) : (fx - fy);
while (!que.empty()){
point cnt = que.front();
que.pop();
if (astep != -1 && cnt.s > astep||cnt.x<0||cnt.x>105000||cnt.s>k){ continue; }
if (cnt.x == fy){
if (astep == -1){ astep = cnt.s; }
else{ astep = astep < cnt.s ? astep : cnt.s; }
continue; }
if (v[cnt.x + 1] == 0){
que.push({ cnt.x + 1, cnt.s + 1 });
v[cnt.x + 1] = 1;
}
if (cnt.x-1>=0&&v[cnt.x - 1] ==0){
que.push({ cnt.x - 1, cnt.s + 1 });
v[cnt.x -1] = 1;
}
if (cnt.x != 0 && v[cnt.x * 2] == 0){
que.push({ cnt.x * 2, cnt.s + 1 });
v[cnt.x*2] = 1; }
}
return ans;
}

int main(){
scanf("%d%d", &fx, &fy);
astep = -1;
beg.x = fx, beg.s = 0;
que.push(beg);
bfs();
printf("%d",astep );
return 0;
}


C - 搜索 中级者向 POJ - 2488

八方向跳棋,求最终整个棋盘都跳满的路径,要求输出路径比较麻烦,dfs过程中在相应的格子记录上这是跳的第几步就行了。

#include<iostream>
#include<string.h>
#include<string>
#include<algorithm>
#include<stdio.h>
using namespace std;
int fx, fy,total;
bool r;
int v[24][24];
int dx[8] = {-1,1,-2,2,-2,2,-1,1};
int dy[8] = {-2,-2,-1,-1,1,1,2,2};

void dfs(int x,int y,int n){
if (r == false)
v[x][y] = n;
if (n == total){
r = true; return; }
for (int i = 0; i < 8; i++){
int nx = x + dx[i], ny = y + dy[i];
if (nx>0 && nx <= fx&&ny > 0 && ny <= fy&&v[nx][ny] == 0&&r==false){
dfs(nx, ny, n + 1);
if (r == true){ break; }
}
}
if (r==false)
v[x][y] = 0;
}

void pf(int x, int y,int n){
putchar(y + 64);
printf("%d", x);
if (n == total){ return; }
for (int i = 0; i < 8; i++){
if (v[x + dx[i]][y + dy[i]] == n + 1){
pf(x + dx[i], y + dy[i], n + 1);
}
}
}

int main(){
int t;
scanf("%d", &t);
for(int k=1;k<=t;k++){
int ax, ay;
r = false;
memset(v, 0, sizeof(v));
scanf("%d%d", &fx, &fy);
total = fx*fy;
for (int i = 1; i <= fx; i++){
for (int j = 1; j <= fy; j++){
dfs(i, j,1);
if (r == true){
ax = i, ay = j;
break; }
}
if (r == true)break;
}

printf("Scenario #%d:\n", k);
if (r == false){ printf("impossible\n\n"); }
else{
pf(ax, ay,1);
printf("\n\n");
}
}
return 0;
}


D - 搜索 初心者向

三维地图bfs最短路径,方向变成6个。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<queue>
using namespace std;
int l, r, c,ans;
int map[32][32][32];
bool v[32][32][32];
int dl[6] = { 0, 0, 0, 0, 1, -1 };
int dx[6] = { -1, 0, 0, 1, 0, 0 };
int dy[6] = { 0, -1, 1, 0, 0, 0 };
struct point{
int l;
int x;
int y;
int s;
}beg;
queue<point> que;
int bfs(){
int ans = -1;
while (!que.empty()){
point cnt = que.front();
que.pop();
if (map[cnt.l][cnt.x][cnt.y]=='E'){ ans = cnt.s; break; }
for (int i = 0; i < 6; i++){
point np={ cnt.l + dl[i], cnt.x + dx[i], cnt.y + dy[i], cnt.s + 1 };
if (np.l >= 0 && np.l<l&&np.x>=0 && np.x<r&&np.y>=0 && np.y < c){
if (map[np.l][np.x][np.y] != '#'&&v[np.l][np.x][np.y]==0){
que.push(np);
v[np.l][np.x][np.y] = 1;
}
}
}
}
while (!que.empty()){
que.pop();
}
return ans;
}

int main(){
while (scanf("%d%d%d", &l, &r, &c)){
memset(v, 0, sizeof(v));
getchar();
if (l == 0){ return 0; }
for (int i = 0; i < l; i++){
for (int j = 0; j < r; j++){
for (int k = 0; k < c; k++){
map[i][j][k]=getchar();
if (map[i][j][k] == 'S'){
beg.l = i, beg.x = j, beg.y = k,beg.s=0;
v[i][j][k] = 1;
}
}
getchar();
}
getchar();
}
que.push(beg);
int ans = bfs();
if (ans == -1){
printf("Trapped!\n");
}
else{
printf("Escaped in %d minute(s).\n",ans);
}
}
return 0;
}


E - 搜索(DFS) 初心者向

连通块计数,经典的dfs

#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stdio.h>
using namespace std;
int n, m;
char map[105][105];
int dx[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int dy[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };

void dfs(int x, int y){
map[x][y] = '.';
for (int i = 0; i < 8; i++){
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 0 && nx < n&&ny >= 0 && ny < m&&map[nx][ny] == 'W'){
dfs(nx, ny);
}
}
}

int main(){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++){
getchar();
for (int j = 0; j < m; j++){
map[i][j] = getchar();
}
}

int ans = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (map[i][j] == 'W'){

dfs(i, j);
ans++;
}
}
}
printf("%d", ans);

return 0;
}


F - 搜索(BFS)+模拟 中级者向 POJ - 3083

给出地图求三种走法的路径:左扶墙,右扶墙,最短路。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<queue>
using namespace std;
int fx, fy;
char map[45][45];
bool v[45][45];
int dx1[4] = { 0, -1, 0, 1, };
int dy1[4] = { 1, 0, -1, 0, };
int dx2[4] = { 0, -1, 0, 1, };
int dy2[4] = { -1, 0, 1, 0, };
struct point{
int x;
int y;
int s;
}beg;
queue<point> que;
int bfs(){
int ans = -1;
while (!que.empty()){
point cnt = que.front();
que.pop();
if (map[cnt.x][cnt.y] == 'E'){ ans = cnt.s; break; }
for (int i = 0; i < 4; i++){
point np = { cnt.x + dx1[i], cnt.y + dy1[i], cnt.s + 1 };
if (np.x >= 0 && np.x<fx&&np.y >= 0 && np.y < fy){
if (map[np.x][np.y] != '#'&&v[np.x][np.y] == 0){
que.push(np);
v[np.x][np.y] = 1;
}
}
}
}
while (!que.empty()){
que.pop();
}
return ans;
}

int dfs(point cnt,int dir){

if (map[cnt.x][cnt.y] == 'E'){
return cnt.s;
}
for (int i = dir-1;; i++){
int ci = i < 0 ? i + 4:i;
point newp = { cnt.x + dx1[ci % 4], cnt.y + dy1[ci % 4], cnt.s + 1 };
if (newp.x >= 0 && newp.x < fx&&newp.y >= 0 && newp.y < fy&&map[newp.x][newp.y] != '#'){

dfs(newp, i);
break;
}
}
}

int idfs(point cnt, int dir){

if (map[cnt.x][cnt.y] == 'E'){
return cnt.s;
}
for (int i = dir-1;; i++){
int ci = i < 0 ? i + 4 : i;
point newp = { cnt.x + dx2[ci % 4], cnt.y + dy2[ci % 4], cnt.s + 1 };
if (newp.x >= 0 && newp.x < fx&&newp.y >= 0 && newp.y < fy&&map[newp.x][newp.y] != '#'){

idfs(newp, i);
break;
}
}
}

int main(){
int t;
scanf("%d", &t);
while (t--){
scanf("%d%d", &fy, &fx);
memset(v, 0, sizeof(v));
getchar();
for (int i = 0; i < fx; i++){
for (int j = 0; j < fy; j++){
map[i][j] = getchar();
if (map[i][j] == 'S'){
beg.x = i, beg.y = j, beg.s = 1;
v[i][j] = 1;
}
}
getchar();
}

que.push(beg);
int ans = bfs();
int ans1 = dfs(beg,0);
int ans2 = idfs(beg, 0);
printf("%d %d %d\n", ans2, ans1, ans);
}
return 0;
}


G - 欧拉图 初心者向 HDU - 1878

判断欧拉回路的题。并查集判连通。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
int n, m;
int point[1005];
int f[1005];
int F(int x){
if (f[x] == x)return x;
else{ return f[x] = F(f[x]); }
}

int main(){
int x, y;
while (~scanf("%d", &n)){
if (n == 0){ return 0; }
scanf("%d", &m);
for (int i = 1; i <= n; i++){
f[i] = i;
}
memset(point, 0, sizeof(point));
for (int j = 0; j < m; j++){
scanf("%d%d", &x, &y);
point[x]++;
point[y]++;
f[F(x)] = F(y);
}

int ji = 0;
int ff = F(1);
for (int i = 1; i <= n; i++){
if ((point[i] % 2) != 0||F(i)!=ff){
ji = 1; break;
}
}
if (ji == 0){ printf("%d\n",1); }
else{ printf("%d\n",0); }
}
return 0;
}


H - 欧拉图 中级者向 POJ - 2230

就是输出一条欧拉回路。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stdio.h>
using namespace std;
#define maxn 50000+10
int n, m;
struct Edge
{
int to;
bool vis;
};
vector<Edge>G[maxn];

void euler(int u)
{
int num = G[u].size();
for (int i = 0; i < num; i++){
if (G[u][i].vis == 0){
G[u][i].vis = 1;
euler(G[u][i].to);
}
}
printf("%d\n", u);
}
int main()
{
scanf("%d%d", &n, &m);
int x, y;
for (int i = 0; i < m; i++){
scanf("%d%d", &x, &y);
Edge a = { y, 0 };
Edge b = { x, 0 };
G[x].push_back(a);
G[y].push_back(b);
}

euler(1);
return 0;
}


I - 欧拉图 上级者向 POJ - 1780

要求把所有可能的密码已最短长度也就是最大的重叠度输出出来,对于n位的密码,答案每往后输出一位,就会与前n-1位构成一个新密码,转换成以n-1位数字为点的欧拉回路,因为除了最后n-1位,一但有一个n-1位数字后面新增0-9都已经在前面输出过了,那么就无法只新增一位来构造一个新密码。

要求非递归,看了别人的代码看了好久才看懂。

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;

int n, ppow[] = { 1, 10, 100, 1000, 10000, 100000, 1000000 };
int cnt[1000000], stack[1000010];
bool vis[1000000];
void dfs(){
memset(vis, 0, sizeof(vis));
//  vis[0] = 1;
memset(cnt, 0, sizeof(cnt));
int top = -1;
stack[++top] = 0;
int total = ppow
;
while (top!=total){
int v = stack[top];
if (cnt[v] ==10 ){
vis[v] = 0; cnt[v] = 0;
top--;
continue;
}
int newn = (v * 10 + cnt[v]) % ppow
;
cnt[v]++;
if (vis[newn]){ continue; }
vis[newn] = 1;
stack[++top] = newn;
}
for (int i = 1; i <= top; ++i) putchar(stack[i] % 10 + '0');
}
int main(){
while (~scanf("%d", &n) && n){
for (int i = 1; i<n; ++i) putchar('0');
dfs();
putchar('\n');
}
return 0;
}


J - 二叉树 中级者向

给出二叉树的前序中序遍历,要求给出后序遍历的结果。分治递归就行。

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <stdio.h>
using namespace std;
int n;
int pre[1005];
int in[1005];
int cou,acount;
void findans(int beg, int end){
if (beg == end){
return;
}
int cnt = pre[cou++];

int mid;
for (int i = beg; i < end; i++){
if (in[i] == cnt){
mid = i;
break;
}
}
findans(beg, mid);
findans(mid + 1, end);
printf("%d", in[mid]);
if (acount <n-1){ printf(" "); }
acount++;
}

int main()
{
while (~scanf("%d", &n)){
cou = 0,acount=0;
for (int i = 0; i < n; i++){
scanf("%d", &pre[i]);
}
for (int i = 0; i < n; i++){
scanf("%d", &in[i]);
}
findans(0, n );
printf("\n");
}
}


K - 二进制枚举 初心者向

输出比给定数字大的只包含4和7且4和7的数量相等的最小数字,枚举每一位是4或7就行。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
long long num;
long long ans;
void dfs(long long n,int fn,int sn){

if (ans!=0&&n >ans||n>num*100 ){ return; }
if (fn == sn&&n>=num){
if (ans == 0){ ans = n; }
else{ ans = ans < n ? ans : n; }
}
dfs(n * 10 + 4,fn+1,sn);
dfs(n * 10 + 7,fn,sn+1);
}

int main(){
while (cin >> num){
ans = 0;
dfs(0, 0, 0);
cout << ans << endl;
}
return 0;
}


L - 二进制枚举 初心者向 HDU - 1557

简单的枚举题。

#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int n;
int p;
int v[25];

int dfs(int x, int y,int num){

if (y == n-1){
if (num > p && (num - v[x] <= p)){ return 1; }
else {return 0;}
}
int ans = 0;
if (y+1 == x){
ans += dfs(x, y + 1, num + v[y+1]);
}
else{
ans += dfs(x, y + 1, num);
ans += dfs(x, y + 1, num + v[y+1]);
}
return ans;
}

int main(){
int t;
cin >> t;
while (t--){
int total = 0;
cin >> n;
for (int i = 0; i < n; i++){
cin >> v[i];
total += v[i];
}
p = total / 2;

for (int i = 0; i < n; i++){
cout << dfs(i, -1, 0);

if (i < n - 1){ cout << " "; }
}
cout << endl;
}
return 0;
}


M - 二进制枚举 初心者向 CodeForces - 202A

求字典序最大的回文字串。

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
using namespace std;
string raw, ans;
int length;

bool pal(string a){
int len = a.length();
bool ans = true;
for (int i = 0; i < len / 2; i++){
if (a[i] != a[len - i - 1]){
ans = false;
break;
}
}
return ans;
}

void dfs(int x,string cnt){
if (pal(cnt)){
if (ans == " "||cnt>ans){
ans = cnt;
}
}
if (x == length - 1){ return; }
dfs(x + 1, cnt + raw[x + 1]);
dfs(x + 1, cnt);
}

int main(){
cin >> raw;
ans = " ";
length = raw.length();
dfs(-1, "");
cout << ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: