搜索=暴力?level高的搜索题也能让你自闭

题目节选自https://blog.csdn.net/q_l_s/article/details/8811534

搜索法在oi赛制里面往往能够骗取少量的分数,如果优化的好,或许还能拿大部分分。

但是在acm赛制,骗分是骗不了的了,我们只能乖乖去想正解,但是对于一道正解就是搜索的题目来讲,往往看起来并没有那么简单,与传统的暴力搜索法的不同,这类题充满着技巧,且优化剪枝的过程稍不注意的话,基本上会超时。

1.八数码问题(洛谷 P1379)

经典题

八数码的八境界:https://www.cnblogs.com/goodness/archive/2010/05/04/1727141.html

第七层境界的代码:

#include <bits/stdc++.h>
#define ri register int
using namespace std;
const int dx[4]={1, -1, 0, 0};
const int dy[4]={0, 0, 1, -1};
const int qq[10]={1,1,2,6,24,120,720,5040,40320,362880};
int ans[4][4]=
{{0,0,0,0},
 {0,1,2,3},
 {0,8,0,4},
 {0,7,6,5}};
struct martrix
{
    int a[4][4];
};
int check(martrix a)
{
    int cnt=0;
    for (ri i=1;i<=3;i++)
        for (ri j=1;j<=3;j++)
            if (a.a[i][j]!=ans[i][j]) cnt++;
    return cnt;
}
int Cantor_unfold(martrix x)
{
    int su = 0;
    int t[10],cnt=-1;
    for (ri i=1;i<=3;i++)
        for (ri j=1;j<=3;j++) t[++cnt]=x.a[i][j];
    for(int i = 0; i < 9; i++)
    {
        int tmp = 0;
        for(int j = 8; j > i; j--)
        {
            if(t[j] < t[i])
                tmp++;
        }
        su += tmp * qq[8-i];
    }    
    return su;
}
struct node
{
    martrix a;
    int x,y,t;
    bool operator<(node x) const{
        return t+check(a)>x.t+check(x.a);
    }
}f;
priority_queue <node> q;
set <int> s;
int i;
string sss;
int main()
{
    getline(cin,sss);
    for (i=0;i<sss.size();i++)
    {
        f.a.a[i/3+1][i%3+1]=sss[i]-'0';
        if (sss[i]=='0') f.x=i/3+1,f.y=i%3+1;
    }
    f.t=0;
    q.push(f);
    while (!q.empty())
    {
        f=q.top();
        q.pop();
        if (!check(f.a))
        {
            
            cout<<f.t;
            return 0;
        }
        for (i=0;i<4;i++)
        {
            int xx=f.x+dx[i];
            int yy=f.y+dy[i];
            if (xx>=1 && xx<=3 && yy>=1 && yy<=3)
            {
                swap(f.a.a[xx][yy],f.a.a[f.x][f.y]);
                int num=Cantor_unfold(f.a);
                if (!s.count(num)) 
                    s.insert(num),q.push({f.a,xx,yy,f.t+1});
                swap(f.a.a[xx][yy],f.a.a[f.x][f.y]);
            }
        }
    }
}
View Code

2.POJ 1084 - Square Destroyer

A*

无限TLE,坑位在此

这里记录一下别人的优秀代码

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
//#include<chrono>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>

using namespace std;

int n,m,deep;

struct node 
{
    bool no[10500];
};

inline int del(int n)
{
    return n*2+1;
}

bool check(node now,int i,int len)
{
    for (int j=i;j<=i+len-1 && j<=m;++j)
        if (now.no[j]) return 1;
    for (int j=i+n,cnt=0;++cnt<=len && j<=m;j+=del(n))
        if (now.no[j]) return 1;
    for (int j=i+n+len,cnt=0;++cnt<=len && j<=m;j+=del(n))
        if (now.no[j]) return 1;
    for (int j=i+len*del(n);j<=i+len*del(n)+len-1 && j<=m;++j)
        if (now.no[j]) return 1;
    return 0;
}

int func(node now)
{
    int sum=0;
    for (int len=1;len<=n;++len)
    {
        for (int k=1,tot=0;k<=m && ++tot<=n-len+1;k+=del(n))
            for (int i=k,S=0;++S<=n-len+1 && i<=m;++i)
            {
                if (check(now,i,len)) continue;
                sum ++;
                for (int j=i;j<=i+len-1 && j<=m;++j) now.no[j]=1;
                for (int j=i+n,cnt=0;++cnt<=len && j<=m;j+=del(n)) now.no[j]=1;
                for (int j=i+n+len,cnt=0;++cnt<=len && j<=m;j+=del(n)) now.no[j]=1;
                for (int j=i+len*del(n);j<=i+len*del(n)+len-1 && j<=m;++j) now.no[j]=1;
            }
    }
    return sum;
}

bool dfs(node now,int x)
{
    if (x==deep)
    {
        if (func(now)==0) 
        {
            cout<<deep<<endl;
            return 1;
        }
        return 0;
    }
    if (x+func(now)>deep) return 0;
    for (int len=1;len<=n;++len)
    {
        for (int k=1,tot=0;k<=m && ++tot<=n-len+1;k+=del(n))
            for (int i=k,S=0;++S<=n-len+1 && i<=m;++i)
            {
                if (check(now,i,len)) continue;
                for (int j=i;j<=i+len-1 && j<=m;++j)
                {
                    now.no[j]=1;
                    if (dfs(now,x+1)) return 1;
                    now.no[j]=0;
                }
                for (int j=i+n,cnt=0;++cnt<=len && j<=m;j+=del(n))
                {
                    now.no[j]=1;
                    if (dfs(now,x+1)) return 1;
                    now.no[j]=0;
                }
                for (int j=i+n+len,cnt=0;++cnt<=len && j<=m;j+=del(n))
                {
                    now.no[j]=1;
                    if (dfs(now,x+1)) return 1;
                    now.no[j]=0;
                }
                for (int j=i+len*del(n);j<=i+len*del(n)+len-1 && j<=m;++j)
                {
                    now.no[j]=1;
                    if (dfs(now,x+1)) return 1;
                    now.no[j]=0;
                }
                return 0;
            }
    }
    return 0;
}

void work(void)
{
    int k;
    cin>>n>>k;
    node st;
    m=2*n*(n+1);
    for (int i=1;i<=m;++i) st.no[i]=0;
    for (int i=1;i<=k;++i) 
    {
        int k;
        cin>>k;
        st.no[k]=1;
    }
    for (deep=0;;++deep) 
        if (dfs(st,0)) return; 
}

int main(void)
{
    int T;
    cin>>T;
    while (T --) work();
    return 0;
}
View Code

3.POJ - 1167 - The Buses

首先我们可以把能够一辆公交出现的车次组成一组的可能的情况预处理出来,把较优的情况先进行搜索,这里我们可以排序一波,同时可以进行剪枝,如果当前包括的几个情况除以剩下的车次大于当前最优答案值,就退出。同时注意一下车次是否会有覆盖的问题即可。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
const int maxn = 2e4+5;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
struct node
{
    int times,interval,start;
};
node a[maxn];
int n,ans,x,m,cnt[65],i,j,k;
bool check(int time,int inter)
{
    while (time<60)
    {
        if (!cnt[time]) return false;
        time+=inter;
    }
    return true;
}
bool cmp(node x,node y)
{
    return x.times>y.times;
}
void dfs(int k,int num,int sum)
{
    if (num==n)
    {
        if (ans>sum) ans=sum;
        return;
    }
    for (int i=k;i<=m;i++)
    {
        if (sum+(n-num)/a[i].times>=ans) return;
        if (!check(a[i].start,a[i].interval)) continue;
        for (int j=a[i].start;j<60;j+=a[i].interval) cnt[j]--;
        dfs(i,num+a[i].times,sum+1);
        for (int j=a[i].start;j<60;j+=a[i].interval) cnt[j]++;
    }
    return;
}
int main()
{
    while (~scanf("%d",&n))
    {
        memset(cnt,0,sizeof(cnt));
        for (i=1;i<=n;i++)
        {
        //    x=read();
            scanf("%d",&x);
            ++cnt[x];
        }
        m=0;
        for (i=0;i<30;i++)
        {
            for (j=i+1;j<60-i;j++)
            {
                if (check(i,j))
                {
                    a[++m].start=i;
                    a[m].interval=j;
                    for (k=a[m].start;k<60;k+=a[m].interval) a[m].times++;
                }
            }
        }
        sort(a+1,a+1+m,cmp);
        ans=17;
        dfs(1,0,0);
        cout<<ans<<endl;
    }
    return 0;
} 
View Code

4.POJ - 1190 - 生日蛋糕

这题看了别人的代码才发现,并没有贪心策略。

直接从下往上枚举高和半径,同时预处理一个当前层的最小体积和侧面积的前缀和,如果超过当前层满足的前缀和,于是退出。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
const int maxn = 101;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
int n,m,minV[maxn],minS[maxn],ans; 
void init()
{
    minV[0]=0,minS[0]=0;
    for (ri i=1;i<22;i++)
    {
        minV[i]=minV[i-1]+i*i*i;
        minS[i]=minS[i-1]+2*i*i;
    }
}
void dfs(int depth,int sum,int try_ans,int r,int h)
{
    if (!depth)
    {
        if (sum==n && try_ans<ans) ans=try_ans;
        return;
    }
    if (try_ans+minS[depth]>ans) return;
    if (sum+minV[depth-1]>n || 2*(n-sum)/r+try_ans>=ans) return;
    for (ri i=r-1;i>=depth;i--)
    {
        if (depth==m) try_ans=i*i;
        int maxh=min((n-sum-minV[depth-1])/(i*i),h-1);
        for (ri j=maxh;j>=depth;j--)
            dfs(depth-1,sum+i*i*j,try_ans+2*i*j,i,j);
    }
}
int main()
{
    init();
    while (~scanf("%d%d",&n,&m))
    {
        ans=INF;
        dfs(m,0,0,n+1,n+1);
        cout<<(ans==INF?0:ans)<<endl;
    }
    return 0;
}
View Code

5.POJ - 1376 - Robot

这题要这么设置状态:当前点位置+当前方向。

bfs

之后就是走和转方向分开写即可。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
const int maxn = 101;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
const int direction[4][2]= {0,-1,-1,0,0,1,1,0};
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
int G[maxn][maxn],vis[maxn][maxn][10],n,m,x,y;
char c[maxn];
struct node
{
    int s,x,y,to;
};
queue <node> q;
void bfs(node a)
{
    node now;
    while (!q.empty()) q.pop();
    q.push(a);
    while (!q.empty())
    {
        now=q.front();
        q.pop();
        if (now.x==x && now.y==y)
        {
            cout<<now.s<<endl;
            return;
        }
        for (ri i=1;i<=3;i++)
        {
            int xx=now.x+direction[now.to][0]*i;
            int yy=now.y+direction[now.to][1]*i;
            if (xx<1 || yy<1 || xx>=n || yy>=m) break;
            if (G[xx][yy] || G[xx+1][yy] || G[xx][yy+1] || G[xx+1][yy+1]) break;
            if (vis[xx][yy][now.to]) continue;
            vis[xx][yy][now.to]=1;
            q.push({now.s+1,xx,yy,now.to});
        }
        for (ri i=0;i<4;i++)
        {
            if (abs(now.to-i)==2) continue;
            if (vis[now.x][now.y][i]) continue;
            vis[now.x][now.y][i]=1;
            q.push({now.s+1,now.x,now.y,i});
        }
    }
    cout<<-1<<endl;
}
int main()
{
    while (~scanf("%d%d",&n,&m))
    {
        if (n==0 && m==0) return 0;
        int i,j;
        node now;
        memset(G,0,sizeof(G));
        memset(vis,0,sizeof(vis));
        for(i=1;i<=n;i++)
            for(j=1;j<=m;j++)
                G[i][j]=read();
        now.x=read(),now.y=read(),x=read(),y=read();
        scanf("%s",c);
        if (G[now.x][now.y] || G[x][y])
        {
            cout<<-1<<endl;
            continue;
        }
        if (c[0]=='w') now.to=0;
        else if (c[0]=='n') now.to=1;
        else if (c[0]=='e') now.to=2;
        else if (c[0]=='s') now.to=3;
        vis[now.x][now.y][now.to]=1;
        now.s=0;
        bfs(now);
    }
    return 0;
}
View Code

6.POJ - 1475 - Pushing Boxes

经典推箱子

bfs+优先队列

由于要推箱子步数少,所以优选当前推箱子步数的情况。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
const int maxn = 101;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
string f[2]={"nesw","NESW"};
const int direction[4][2]={{-1,0},{0,1},{1,0},{0,-1}};
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
struct node
{
    int Sx,Sy,Bx,By;
    int pt,t;
    string s;
    bool operator < (const node &a) const
    {
        if(pt==a.pt)
            return t>a.t;
        return pt>a.pt;
    }
};
int n,m,Sx,Sy,Bx,By,vis[25][25][25][25],cnt;
char G[25][25];
bool check(int xx,int yy)
{
    if (xx>=1 && xx<=n && yy>=1&& yy<=m) return true;
    return false;
}
//void bfs(int Sx,int Sy,int Bx,int By)

void bfs()
{
    node now;
    priority_queue<node> q;
    q.push({Sx,Sy,Bx,By,0,0,""});
    while (!q.empty())
    {
        now=q.top();
        q.pop();
        if (G[now.Bx][now.By]=='T')
        {
            cout<<now.s<<endl;
            return;
        }
        for (int i=0;i<4;i++)
        {
            int xx=now.Sx+direction[i][0];
            int yy=now.Sy+direction[i][1];
            int xxx=xx+direction[i][0];
            int yyy=yy+direction[i][1];
            //if (xx>=1 && xx<=n && yy>=1&& yy<=m)
            if (check(xx,yy) && G[xx][yy]!='#')
            {
                if (xx==now.Bx && yy==now.By)
                {
                    if (check(xxx,yyy) && G[xxx][yyy]!='#' && vis[xx][yy][xxx][yyy]==0)
                    {
                        vis[xx][yy][xxx][yyy]=1;
                        string s=now.s;
                        s+=f[1][i];
                        q.push({xx,yy,xxx,yyy,now.pt+1,now.t+1,s});
                    }
                }
                else
                if (vis[xx][yy][now.Bx][now.By]==0)
                {
                    vis[xx][yy][now.Bx][now.By]=1;
                    string s=now.s;
                    s+=f[0][i];
                    q.push({xx,yy,now.Bx,now.By,now.pt,now.t+1,s});
                }
                
            }
        }
    }
    printf("Impossible.
");
}
int main()
{
//    debug;
    cnt=0;
    while (~scanf("%d%d",&n,&m))
    {
        if (n==0 && m==0) return 0;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++) 
        {
            scanf("%s",G[i]+1);
            for (int j=1;j<=m;j++)
            {
                if (G[i][j]=='S')
                {
                    Sx=i;
                    Sy=j;        
                }        
                if (G[i][j]=='B')
                {
                    Bx=i;
                    By=j;
                }
            }
        }
        printf("Maze #%d
",++cnt);
        vis[Sx][Sy][Bx][By]=1;
        //bfs(Sx,Sy,Bx,By);
        bfs();
        cout<<endl;
    }
}
View Code

7.POJ - 2449 - Remmarguts' Date

K短路模板

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 1001;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
struct node
{
    int v,value;
};
vector <node> G[maxn],GG[maxn];
int dis[maxn],x,y,v,k,n,m,cnt[maxn];
bool vis[maxn];
priority_queue<pii,vector<pii>,greater<pii> > q;
void dijkstra()
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[y]=0;
    q.push(mp(0,y));
    while (!q.empty())
    {
        int u=q.top().second;
        q.pop();
        if (vis[u]) continue;
        vis[u]=1;
        for (auto x:GG[u])
        {
            int v=x.v;
            int value=x.value;
            if (vis[v]) continue;
            if (dis[v]>dis[u]+value)
            {
                dis[v]=dis[u]+value;
                q.push(mp(dis[v],v));
            }
        }
    }
}
int Astar()
{
    memset(cnt,0,sizeof(cnt));
    q.push(mp(dis[x],x));
    while (!q.empty())
    {
        int u=q.top().second;
        int d=q.top().first-dis[u];
        q.pop();
        cnt[u]++;
        if (cnt[y]==k) return d;
        for (auto x:G[u])
        {
            int v=x.v;
            int value=x.value;
            if (cnt[v]<k) q.push(mp(d+value+dis[v],v));
        }
    }
    return -1;
}
int main()
{
    n=read(),m=read();
    for (int i=1;i<=m;i++)
    {
        x=read(),y=read(),v=read();
        G[x].push_back({y,v});
        GG[y].push_back({x,v});
    }
    x=read(),y=read(),k=read();
    if (x==y) k++;
    dijkstra();
    cout<<Astar()<<endl;
    return 0;
}
View Code

8.POJ - 2908 - Quantum

事实证明这题偷懒是不行的,状态要位操作才能过的了。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 50;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
char c[maxn][maxn],c1[maxn],c2[maxn],c3[maxn];
int a[maxn],ans,l,n,m;
bool vis[(1<<22)+5];
struct node
{
        char s[maxn];
    int ans;
    friend bool operator<(node x,node y) 
    {
        return x.ans > y.ans;
    }
};
int vs(char k[])
{
    int s=0;
    int i=0;
    while(k[i++])
        s=s*2+k[i-1]-'0';
    return s;
}
void vc(char s1[],char s2[])
{
    for(int i=0;i<l;i++)
    {
        if(s2[i]=='N')
            c3[i]=s1[i];
        if(s2[i]=='F')
        {
            if(s1[i]=='0')
                c3[i]='1';
            if(s1[i]=='1')
                c3[i]='0';
        }
        if(s2[i]=='S')
            c3[i]='1';
        if(s2[i]=='C')
            c3[i]='0';
    }
}
void dfs()
{
    memset(vis,0,sizeof(vis));
    priority_queue <node> q;
    node now;
    now.ans=0;
    strcpy(now.s,c1);
    q.push(now);
    while (!q.empty())
    {
        now=q.top();
        q.pop();
        if (vis[vs(now.s)]) continue;
        if (strcmp(now.s,c2)==0)
        {
            ans=now.ans;
            break;
        }
        vis[vs(now.s)]=1;
        for (ri i=1;i<=n;i++)
        {
            vc(now.s,c[i]);
            if (!vis[vs(c3)])
            {
                node k1;
                strcpy(k1.s,c3);
                k1.ans=now.ans+a[i];
                q.push(k1);
            }
        }
    }
}
int main()
{
    int t,i;
//    debug;
    t=read();
    while (t--)
    {
        scanf("%d%d%d",&l,&n,&m);
        for (i=1;i<=n;i++) 
        {
            scanf("%s%d",c[i],&a[i]);
        }
        for (i=1;i<=m;i++)
        {
             memset(c3,0,sizeof(c3));
            scanf("%s%s",c1,c2);
            //cout<<c2<<endl;
            ans=INF;
            dfs();
            if (ans==INF) cout<<"NP"<<" ";
                else cout<<ans<<" ";
        }
        cout<<endl;
    }
    return 0;
}
View Code

9.POJ - 3460 - Booksort

这题估价函数相当难想

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<vector>
#include<list>
#include<queue>
#include<string>
#include<set>
#include<map>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 22;
const int INF = 0x3f3f3f3f; 
const int mod = 998244353;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
struct node
{
    int a[maxn];
};
int ans,n,t;
int cal(int s[])
{
    int ans=0;
    for (ri i=1;i<n;i++)
        if (s[i]+1!=s[i+1]) ans++;
    return ceil(ans/3.0);
}
node upgrade(node x,int l,int r,int len)
{
    node y;
    y=x;
    for (ri i=l;i<l+len;i++)
        x.a[r-len-l+i+1]=y.a[i];
    for (ri i=l+len;i<=r;i++)
        x.a[i-len]=y.a[i];
    return x;
}
bool check(int s[])
{
    for(int i=1; i<n; i++)
        if(s[i] + 1 != s[i+1])
            return 0;
    return 1;
}
bool dfs(node q,int x,int lim)
{
    if (x+cal(q.a)>lim)
    {
        return false;
    }
    if (check(q.a)) return true;
    for (ri i=1;i<n;i++)
    {
        for (ri j=1;i+j-1<=n;j++)
        {
            for (ri k=i+j;k<=n;k++)
            {
                if (dfs(upgrade(q,j,k,i),x+1,lim)) return true;
            }
        }
    }
    return false;
}
int main()
{
//    debug;
    t=read();
    node k;
    while (t--)
    {
        n=read();
    
        for (int i=1;i<=n;i++) k.a[i]=read();
        for(int i=0; i<5; i++)
        {
            if(dfs(k,0,i))
            {
                printf("%d
",i);
                break;
            }
            else if(i == 4)printf("5 or more
");

        }
    }
    return 0;
}
View Code

10.9×9数独

这种题可用舞蹈链来写,然而我不会,爆搜才有我的份。

#include<bits/stdc++.h>
using namespace std;
int a[100][100];
int cnt,flag;
int judge(int x,int y,int t)
{
    for(int i=0;i<9;i++)
    {
        if (a[i][y]==t) return 0;
        if (a[x][i]==t)
            return 0;
    }
    x=x/3*3;
    y=y/3*3;
    for(int i=x;i<x+3;i++)
        for(int j=y;j<y+3;j++)
        {
            if(a[i][j]==t) return 0;
        }
    return 1;
}
void dfs(int dep)
{
    if(dep==81)
    {
        for(int i=0;i<9;i++)
        {
            for(int j=0;j<9;j++)
                cout<<a[i][j]<<" ";
            cout<<endl;
        }
        return;
    }
    int ex = dep/9;
    int ey = dep%9;
    if(a[ex][ey]!=0)
        dfs(dep+1);
    else 
    {
        for(int i=1;i<10;i++)
        {
            if(judge(ex,ey,i))
            {
                a[ex][ey] = i;
                dfs(dep);
                a[ex][ey] = 0;
            }
        }
        return;
    }
     
}
int main()
{
    int i,j;
    for(i=0;i<9;i++)
        for(j=0;j<9;j++)
            cin>>a[i][j];
    cnt=flag=0;
    dfs(0);
    return 0;
}
View Code

搜索题出问题要么就是超时,要么就是各种小错误,前者解决问题方法大多都是找更优的剪枝方法,后者解决问题方法基本上就是干瞪眼找错了,因此一旦搜索的姿势没对,这种题耗时又耗精力。多练才是王道。

原文地址:https://www.cnblogs.com/Y-Knightqin/p/12657394.html