hdu11周赛D题s素数环问题

一道经典的dfs,然而我找bug找了五个小时(发现很多问题,写在注释里)最后发现超时了。。。我真是。。。但是还是能反映很多问题的。
先放我超时的代码(又臭又长)

#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n;
int z=0,sum=-1;                                    //z第几个方案
int a[25],flag[25];                                   //a里面存放可能数字,其实这里不用开数组,刚开始想多了,用变量就行。flag表示是否访问过
struct point
{
    int x[25];
}answer[10000];                                   //由于最后要按最小字典序输出,所以定义结构体,每个结构体里面放一种可能顺序
bool sushuceshi(int n1)
{
    if(n1==2)return true;
    if((n1&1)==0)return false;
    for(int i=3;i*i<=n1;i+=2)
        if(n1%i==0)return false;
    return true;
}
int dfs(int xh,int d,int z)
{
    if(!sushuceshi(a[xh]+answer[z].x[d-1]))return 0;
    if(d==n-1)
    {
        if(sushuceshi(a[xh]+1))
        {if(z>sum)sum=z;                                         //为了使方案数能都叠加
        answer[z].x[d]=a[xh];flag[xh]=0;return 1;}
        else return 0;
    }
    flag[xh]=1;
    answer[z].x[d]=a[xh];
    int flag1=0;
    for(int i=0;i<n;i++)
        if(flag[i]==0)
        if(dfs(i,d+1,z)!=0)
            {flag1++;                                                     //不可以直接return,有多种可能比如说123或者124如果选择3就return那么4就没选到。下面的z表示提供新的方案
             z++;
             for(int e=0;e<=d;e++)
             answer[z].x[e]=answer[z-1].x[e];               //给新的方案前面的数赋值,这里注意要赋初值啊,没有给e赋初值找了几个小时的bug
                flag[i]=0;}                                                   //新的方案,所以123中的3要变回没被访问过
        if(flag1!=0)return 1;
    flag[xh]=0;                                                             //选择一个数但后面的数都不可以比如说选择2然后123不可以124不可以12。。都不行那么2就不行
    return 0;
}
bool cmp(const point&a,const point&c)                   //字典序
{
    for(int i=0;i<n;i++)
    {
        if(a.x[i]<c.x[i])return true;
        else if(a.x[i]>c.x[i])return false;
    }
    return true;
}
int main()
{
    while(cin>>n)
    {
        z=0;
        memset(flag,0,sizeof(flag));
        for(int i=0;i<n;i++)a[i]=i+1;
        answer[0].x[0]=1;
        flag[0]=1;
        int d=0;
        for(int i=1;i<n;i++)
            if(dfs(i,d+1,z)!=0)
            {
            z=sum+1;                                                         //更新x值
            answer[z].x[0]=1;
            memset(flag,0,sizeof(flag));
            flag[0]=1;}
          sort(answer,answer+z,cmp);
          for(int i=0;i<z;i++)
          {
              for(int w=0;w<n;w++)
                cout<<answer[i].x[w]<<" ";
              cout<<endl;
          }
    }
}

总的来说,思路就是,首先每个方案第一个值都为1然后dfs输入选择的数字(a数组中数字的下标)还有次序(在环里面是第几个)
如果前面一个和当下这个数字和为素数那么就标记访问,标记次序数组(answer【z】。x【d】)的值,然后再去选择下一个(for循环)。
每次选择完下一个返回时记得增加z(方案数)的值,并且将原来对下一个选择的操作全部清空,在选择新的看看有没有新的方案(保证可以出现1 2 3 8 5 6 7 4和1 2 5 8 3 4 7 6两种方案都在)
输出时不用考虑顺时针或逆时针,dfs在搜索时本来就找到了。
样例过了,但是T了,其实这里面有一个问题就是你不知道有多少个方案,也就是answer你不知道开多少组。

看了一下题解。发现自己真是个睿智。搜索本来就是最小字典序了,所以不需要结构体。把代码相应结构体删了之后再改了一下。发上去pe再看了一下有几个注意点:
1.每一个case都要空行!
2.每一组方案最后不要空格直接换行(跳过一个坑没想到这里居然没看到)
然后ac了,以下代码

#include<iostream>//(16.07)
#include<string.h>
using namespace std;
int n;
int a[25],flag[25];
int sum=0,i=1;
bool sushuceshi(int n1)
{
    if(n1==2)return true;
    if((n1&1)==0)return false;
    for(int i=3;i*i<=n1;i+=2)
        if(n1%i==0)return false;
    return true;
}
void dfs(int sz,int d)
{
    if(!sushuceshi(sz+a[d-1]))return;
    if(d==n-1)
    {
        if(sushuceshi(sz+1))
            {a[d]=sz;flag[sz]=0;
            for(int e=0;e<=d;e++)
            {cout<<a[e];
            if(e!=d)cout<<" ";}
            cout<<endl;sum++;
            }
    }
    flag[sz]=1;
    a[d]=sz;
    for(int i=1;i<=n;i++)
        if(flag[i]==0){dfs(i,d+1);flag[i]=0;}
}
int main()
{
    while(cin>>n)
    {
        cout<<"Case "<<i<<":"<<endl;i++;
        memset(flag,0,sizeof(flag));
        flag[1]=1;
        if(n==1)cout<<"1"<<endl;
        for(int i=2;i<=n;i++)
        {a[0]=1;dfs(i,1);flag[i]=0;}
        cout<<endl;
        }
     }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值