0x29 总结与练习

搜索真的菜。。困扰了很久,上个星期天没休息好导致整个礼拜没有精神。。

大概完成得七七八八了吧。真是深切的体会到暴力出奇迹的疯狂啊。

3、虫食算 从末位开始枚举判断,通过加数可以推出和的字母代表的数。那么加一个剪枝,就是通过当前所知字母对应值判断是否合法。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int n,cnt,a[30],c[30];bool bk,v[30];
char ss[3][30];
bool check(int k)
{
    for(int i=k-1;i>=1;i--)
    {
        if(a[ss[0][i]-'A'+1]!=-1&&a[ss[1][i]-'A'+1]!=-1)
        {
            int d=a[ss[0][i]-'A'+1]+a[ss[1][i]-'A'+1];
            if(a[ss[2][i]-'A'+1]!=-1)
            {
                int dd=a[ss[2][i]-'A'+1];
                if(dd==d%n||dd==(d+1)%n)continue;
                return false;
            }
        }
    }
    return true;
}
void dfs(int k,int w)
{
    if(bk==true)return ;
    if(cnt==n||(k==0&&c[k]==0))
    {
        bk=true;
        for(int i=1;i<n;i++)printf("%d ",a[i]);
        printf("%d\n",a[n]);
        return ;
    }
    if(w==2)
    {
        int x=ss[w][k]-'A'+1;
        int d=a[ss[0][k]-'A'+1]+a[ss[1][k]-'A'+1]+c[k];
        
        if(a[x]==-1)
        {
            if(v[d%n]==true)return ;
            
            a[x]=d%n;c[k-1]=d/n;v[d%n]=true;cnt++;
            if(check(k))dfs(k-1,0);
            a[x]=-1;c[k-1]=0;v[d%n]=false;cnt--;
        }
        else if(a[x]==d%n)
        {
            c[k-1]=d/n;
            dfs(k-1,0);
            c[k-1]=0;
        }
    }
    else
    {
        int x=ss[w][k]-'A'+1;
        if(a[x]==-1)
        {
            for(int i=0;i<n;i++)
            {
                if(v[i]==false)
                {
                    a[x]=i;v[i]=true;cnt++;
                    if(check(k))dfs(k,w+1);
                    a[x]=-1;v[i]=false;cnt--;
                }
            }
        }
        else dfs(k,w+1);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<3;i++)scanf("%s",ss[i]+1);
    memset(a,-1,sizeof(a));
    memset(c,0,sizeof(c));
    memset(v,false,sizeof(v));
    bk=false;cnt=0;dfs(n,0);
    return 0;
}
虫食算

4、Mayan游戏 直接枚举移动方案并模拟状态的转移,hash判重就OK了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;

int n,cnt,len[10],a[10][10];bool bk;
struct ansnode{int x,y,z;}as[10];

bool del[10][10];
void change(int x,int y,int z)
{
    if(len[x+z]>=y)swap(a[x+z][y],a[x][y]);
    else 
    {
        a[x+z][++len[x+z]]=a[x][y];
        for(int i=y;i<=len[x];i++)swap(a[x][i],a[x][i+1]);
        a[x][len[x]]=0;len[x]--;
    }
    memset(del,false,sizeof(del));
    bool qwq=true;
    while(qwq)
    {
        qwq=false;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=len[i];j++)
            {
                if(i<=3)
                {
                    if(a[i][j]==a[i+1][j]&&a[i+1][j]==a[i+2][j])
                    {
                        del[i][j]=true, del[i+1][j]=true, del[i+2][j]=true;
                        qwq=true;
                    }
                }
                if(len[i]-j>=2)
                {
                    if(a[i][j]==a[i][j+1]&&a[i][j+1]==a[i][j+2])
                    {
                        del[i][j]=true, del[i][j+1]=true, del[i][j+2]=true;
                        qwq=true;
                    }
                }
            }
        for(int i=1;i<=5;i++)
        {
            int tp=0;
            for(int j=1;j<=len[i];j++)
                if(del[i][j]==false)a[i][++tp]=a[i][j];
                else cnt--;
            for(int j=tp+1;j<=len[i];j++)a[i][j]=0;
            len[i]=tp;
        }
        memset(del,false,sizeof(del));
    }
}
map<int,bool>mp;
bool myhash(int k)
{
    int d=k;
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=len[i];j++)d=d*11+a[i][j];
        d=d*11;
    }
    if(mp[d]==true)return true;
    else {mp[d]=true;return false;}
}
void dfs(int k)
{
    if(bk==true)return ;
    if(cnt==0&&k==n+1)
    {
        for(int i=1;i<=n;i++)printf("%d %d %d\n",as[i].x-1,as[i].y-1,as[i].z);
        bk=true;return ;
    }
    if(cnt==0||k==n+1)return ;
    
    int tlen[10],t[10][10],tcnt;
    tcnt=cnt;
    memcpy(tlen,len,sizeof(tlen));
    memcpy(t,a,sizeof(t));
    for(int i=1;i<=5;i++)
    {
        for(int j=1;j<=len[i];j++)
        {
            if(i!=5)
            {
                change(i,j,1);
                as[k].x=i, as[k].y=j, as[k].z=1;
                if(!myhash(k))
                    dfs(k+1);
                as[k].x=0, as[k].y=0, as[k].z=0;
                
                cnt=tcnt;
                memcpy(len,tlen,sizeof(len));
                memcpy(a,t,sizeof(a));
            }
            if(i!=1)
            {
                change(i,j,-1);
                as[k].x=i, as[k].y=j, as[k].z=-1;
                if(!myhash(k))
                    dfs(k+1);
                as[k].x=0, as[k].y=0, as[k].z=0;
                
                cnt=tcnt;
                memcpy(len,tlen,sizeof(len));
                memcpy(a,t,sizeof(a));
            }
        }
    }
}
int main()
{
    scanf("%d",&n);
    memset(len,0,sizeof(len));
    for(int i=1;i<=5;i++)
    {
        while(scanf("%d",&a[i][++len[i]])!=EOF){if(a[i][len[i]]==0)break;}
        len[i]--;cnt+=len[i];
    }
    bk=false;dfs(1);
    if(bk==false)printf("-1\n");
    return 0;
}
Mayan游戏

5、poj1167 (题意真星星的难理解)现在也学乖了啊,对于这种分组的题要么就是填满一组又一组要么就是一个个加,这里的话是用一个个加的(因为我一开始写的一组又一组TLE啦:)),可以暴力把所有分组方案求出,从多到少填,其中要判断因为前面选了导致现在不合法。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int n,ans,ti[110];
struct line{int st,jg,c;}l[4100];int len;
bool cmp(line l1,line l2){return l1.c>l2.c;}

bool check(int t,int jg)
{
    while(t<60)
    {
        if(ti[t]==0)return false;
        t+=jg;
    }
    return true;
}
void dfs(int k,int sum,int last)
{
    if(sum==0){ans=min(ans,k);return ;}
    for(int i=last;i<=len;i++)
    {
        if(k+sum/l[i].c>=ans)break;
        if(check(l[i].st,l[i].jg))
        {
            for(int t=l[i].st;t<60;t+=l[i].jg)ti[t]--;
            dfs(k+1,sum-l[i].c,i);
            for(int t=l[i].st;t<60;t+=l[i].jg)ti[t]++;
        }
    }
}
int main()
{
    int x;
    while(scanf("%d",&n)!=EOF)
    {
        memset(ti,0,sizeof(ti));
        for(int i=1;i<=n;i++)
            scanf("%d",&x),ti[x]++;
        len=0;
        for(int st=0;st<30;st++)
            for(int jg=st+1;st+jg<60;jg++)
                if(check(st,jg))
                {
                    len++;
                    l[len].st=st;
                    l[len].jg=jg;
                    l[len].c=(59-st)/jg+1;
                }
        sort(l+1,l+len+1,cmp);
                
        ans=17;
        dfs(0,n,1);
        printf("%d\n",ans);
    }
    return 0;
}
poj1167

6、poj3700 这里还是一个个填,有四种情况,开一个新的上升/下降区间,or加入一个以前的上升/下降区间,单论上升,假如可以加入以前的上升区间,根据贪心的思想肯定选比自己小而且最大的那个更新,更加关键的是无需尝试新开一个,这也是贪心等效性的思想。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int n,ans,c[110],slen[2],s[2][110];
bool dfs(int k)
{
    if(slen[0]+slen[1]>=ans+1)return false;
    if(k==n+1)return true;
    
    int id,t;
    id=-1;
    for(int i=1;i<=slen[0];i++)
    {
        if(s[0][i]<c[k])
            if(id==-1||s[0][i]>s[0][id])id=i;
    }
    if(id!=-1)
    {
        t=s[0][id];s[0][id]=c[k];
        if(dfs(k+1))return true;
        s[0][id]=t;
    }
    else
    {
        s[0][++slen[0]]=c[k];
        if(dfs(k+1))return true;
        s[0][slen[0]--]=0;
    }
    
    id=-1;
    for(int i=1;i<=slen[1];i++)
    {
        if(s[1][i]>c[k])
            if(id==-1||s[1][i]<s[1][id])id=i;
    }
    if(id!=-1)
    {
        t=s[1][id];s[1][id]=c[k];
        if(dfs(k+1))return true;
        s[1][id]=t;
    }
    else
    {
        s[1][++slen[1]]=c[k];
        if(dfs(k+1))return true;
        s[1][slen[1]--]=0;
    }
    return false;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        for(int i=1;i<=n;i++)scanf("%d",&c[i]);
        slen[0]=slen[1]=0;
        memset(s,0,sizeof(s));
        for(ans=1;;ans++)
        {
            if(dfs(1))break;
        }
        printf("%d\n",ans);
    }
    
    return 0;
}
poj3700

7、8、放到练习是侮辱智商??

9、子串变换 这题跑的挺快啊0ms,我还以为我写的这么又丑又慢会被卡,强行双向bfs,用KMP找子串相等,直接暴力转移状态,然后hash一下判重就差不多了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;

char sc[2][30],ss[2][10][30];
struct node
{
    char sl[30];LL d;
}list[2][110000];char sp[30],su[30];
map<LL,int>d[2];

int p[30];
int KMP(int w,int k,int be)
{
    p[1]=0;int j=0,len=strlen(ss[w][k]+1);
    for(int i=2;i<=len;i++)
    {
        while(j>0&&ss[w][k][i]!=ss[w][k][j+1])j=p[j];
        if(ss[w][k][i]==ss[w][k][j+1])j++;
        p[i]=j;
    }
    j=0;int splen=strlen(sp+1);
    for(int i=1;i<=splen;i++)
    {
        while(j>0&&sp[i]!=ss[w][k][j+1])j=p[j];
        if(sp[i]==ss[w][k][j+1])j++;
        if(j==len&&i-len+1>be)return i-len+1;
    }
    return -1;
}

map<LL,bool>mp[2];
int myhash()
{
    int sulen=strlen(su+1);LL d=0;
    for(int i=1;i<=sulen;i++)d=d*93LL+(LL(su[i]));
    return d;
}

int main()
{
    scanf("%s",sc[0]+1);scanf("%s",sc[1]+1);
    int n=0;
    while(scanf("%s",ss[0][++n]+1)!=EOF){scanf("%s",ss[1][n]+1);}
    n--;
    
    int head[2],tail[2];
    
    head[0]=1;tail[0]=2;
    memcpy(list[0][1].sl,sc[0],sizeof(list[0][1].sl));
    memcpy(su,sc[0],sizeof(su));
    list[0][1].d=myhash();mp[0][list[0][1].d]=true;
    d[0][list[0][1].d]=0;
    memset(su,0,sizeof(su));
    
    head[1]=1;tail[1]=2;
    memcpy(list[1][1].sl,sc[1],sizeof(list[1][1].sl));
    memcpy(su,sc[1],sizeof(su));
    list[1][1].d=myhash();mp[1][list[1][1].d]=true;
    d[1][list[1][1].d]=0;
    memset(su,0,sizeof(su));
    
    //--------------init----------------------
    
    while(head[0]<tail[0]&&head[1]<tail[1])
    {
        memcpy(sp,list[0][head[0]].sl,sizeof(sp));int splen=strlen(sp+1);
        LL spd=list[0][head[0]].d;
        if(mp[0][spd]&mp[1][spd]){printf("%d\n",d[0][spd]+d[1][spd]);return 0;}
        for(int i=1;i<=n&&d[0][spd]<=6;i++)
        {
            int be=KMP(0,i,0);
            while(be!=-1)
            {
                int len0=strlen(ss[0][i]+1),len1=strlen(ss[1][i]+1);
                if(splen-len0+len1>25)break;
                int sulen=0;
                for(int j=1;j<be;j++)su[++sulen]=sp[j];
                for(int j=1;j<=len1;j++)su[++sulen]=ss[1][i][j];
                for(int j=be+len0;j<=splen;j++)su[++sulen]=sp[j];
                
                LL sud=myhash();
                if(!mp[0][sud])
                {
                    mp[0][sud]=true;d[0][sud]=d[0][spd]+1;
                    memcpy(list[0][tail[0]].sl,su,sizeof(list[0][tail[0]].sl));
                    list[0][tail[0]].d=sud;
                    tail[0]++;
                }
                memset(su,0,sizeof(su));
                
                be=KMP(0,i,be);
            }
        }
        head[0]++;
        
        
        memcpy(sp,list[1][head[1]].sl,sizeof(sp));splen=strlen(sp+1);
        spd=list[1][head[1]].d;
        if(mp[0][spd]&mp[1][spd]){printf("%d\n",d[0][spd]+d[1][spd]);return 0;}
        for(int i=1;i<=n&&d[1][spd]<=6;i++)
        {
            int be=KMP(1,i,0);
            while(be!=-1)
            {
                int len0=strlen(ss[0][i]+1),len1=strlen(ss[1][i]+1);
                if(splen-len1+len0>25)break;
                int sulen=0;
                for(int j=1;j<be;j++)su[++sulen]=sp[j];
                for(int j=1;j<=len0;j++)su[++sulen]=ss[0][i][j];
                for(int j=be+len1;j<=splen;j++)su[++sulen]=sp[j];
                
                LL sud=myhash();
                if(!mp[1][sud])
                {
                    mp[1][sud]=true;d[1][sud]=d[1][spd]+1;
                    memcpy(list[1][tail[1]].sl,su,sizeof(list[1][tail[1]].sl));
                    list[1][tail[1]].d=sud;
                    tail[1]++;
                }
                memset(su,0,sizeof(su));
                
                be=KMP(1,i,be);
            }
        }
        head[1]++;
    }
    printf("NO ANSWER!\n");
    return 0;
}
子串变换

10、poj2044 二进制表示状态,记录四个角落多久没降雨,判重即可。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int Bin[30];
const int dx[9]={0,-2,-1,0,0,1,2,0,0};
const int dy[9]={0,0,0,-2,-1,0,0,1,2};

int n,u[410];
bool v[370][9][7][7][7][7];
int point(int x,int y){return (x-1)*4+y;}
bool check(int k,int x,int y)
{
    int zt=0;
    zt^=Bin[point(x,y)];
    zt^=Bin[point(x+1,y)];
    zt^=Bin[point(x,y+1)];
    zt^=Bin[point(x+1,y+1)];
    return (0<x)&&(x<=3)&&(0<y)&&(y<=3)&&(!(zt&u[k]));
}
int dfs(int k,int x,int y,int rain[4])
{
    if(k==n+1)return 1;
    if(v[k][point(x,y)][rain[0]][rain[1]][rain[2]][rain[3]])return 0;
    v[k][point(x,y)][rain[0]][rain[1]][rain[2]][rain[3]]=true;
    for(int i=0;i<=8;i++)
    {
        int tx=x+dx[i],ty=y+dy[i];
        int train[4];memcpy(train,rain,sizeof(train));
        for(int j=0;j<=3;j++)train[j]++;
        if(tx==1&&ty==1)train[0]=0;
        if(tx==3&&ty==1)train[1]=0;
        if(tx==1&&ty==3)train[2]=0;
        if(tx==3&&ty==3)train[3]=0;
        if(check(k,tx,ty)&&train[0]<=6&&train[1]<=6&&train[2]<=6&&train[3]<=6)
        {
            if(dfs(k+1,tx,ty,train))return 1;
        }
        if(k==1)break;
    }
    return 0;
}

int main()
{
    Bin[1]=1;for(int i=2;i<=20;i++)Bin[i]=Bin[i-1]*2;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        
        for(int i=1;i<=n;i++)
        {
            u[i]=0;int x;
            for(int j=1;j<=16;j++)
            {
                scanf("%d",&x);
                if(x==1)u[i]^=Bin[j];
            }
        }
        memset(v,false,sizeof(v));
        int rain[4];memset(rain,0,sizeof(rain));
        printf("%d\n",dfs(1,2,2,rain));
    }
    return 0;
}
poj2044

11、留坑

12、poj1945 这题真的是很奇淫了,较小数不能超过100?gc控到50都没问题

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

struct node
{
    int x,y,c;
}list[1100000];int head,tail;
bool mp[110][410000];
void insert(int x,int y,int c)
{
    if(x>y)swap(x,y);
    if(y>400000||x>100||x<0||mp[x][y])return ;
    mp[x][y]=true;
    
    list[tail].x=x,list[tail].y=y,list[tail].c=c;
    tail++;if(tail==1050000)tail=1;
}

int main()
{
    int k;
    scanf("%d",&k);
    head=1,tail=2;
    list[head].x=0,list[head].y=1,list[head].c=0;
    mp[0][1]=true;
    while(head!=tail)
    {
        int x=list[head].x,y=list[head].y,c=list[head].c;
        if(x== k||y==k){printf("%d\n",c);break;}
        insert(x,x+y,c+1), insert(y,x+y,c+1);
        insert(y-x,y,c+1), insert(y-x,x,c+1);
        insert(x*2,y,c+1), insert(x,y*2,c+1);
        insert(x,x*2,c+1), insert(y,y*2,c+1);
        head++;if(head==1050000)head=1;
    }
    return 0;
}
poj1945

13、poj4007 迭代加深,暴力dfs+bfs找被覆盖的点,当时我满脑子的都是神之折纸的个游戏啊,怎么IDA*,我玩的时候看到步数比颜色少就重来,但是这个故意卡好像。。结果gc%了一发就是这么搞?真是。。。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
const int dx[4]={-1,0,1,0};
const int dy[4]={0,-1,0,1};

int n,cnt,a[10][10];

int xx[110],yy[110];bool v[10][10];
bool check(int x,int y,int c){return 0<x&&x<=n&&0<y&&y<=n&&a[x][y]==c;}
int bfs(int c)
{
    int head=1,tail=2,cg=0;xx[1]=1,yy[1]=1;
    memset(v,false,sizeof(v));v[1][1]=true;
    while(head<tail)
    {
        int x=xx[head],y=yy[head];
        for(int i=0;i<=3;i++)
        {
            int tx=x+dx[i],ty=y+dy[i];
            if((check(tx,ty,c)||a[tx][ty]==-1)&&v[tx][ty]==false)
            {
                if(a[tx][ty]!=-1)cg++;
                v[tx][ty]=true;a[tx][ty]=-1;
                xx[tail]=tx;yy[tail]=ty;
                tail++;
            }
        }
        head++;
    }
    return cg;
}
bool bb[10];
int count()
{
    memset(bb,false,sizeof(bb));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            if(a[i][j]!=-1)bb[a[i][j]]=true;
    int c=0;
    for(int i=0;i<=5;i++)
        if(bb[i]==true)c++;
    return c;
}
int ans;
bool dfs(int k)
{
    if(k+count()>ans)return false;
    if(cnt==0)return true;
    
    int t[10][10];
    for(int c=0;c<=5;c++)
    {
        memcpy(t,a,sizeof(t));
        int d=bfs(c);
        if(d>0)
        {
            cnt-=d;
            if(dfs(k+1))return true;
            cnt+=d;
        }
        memcpy(a,t,sizeof(a));
    }
    return false;
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)break;
        cnt=n*n;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                scanf("%d",&a[i][j]);
        int c=a[1][1];
        cnt--;a[1][1]=-1;
        cnt-=bfs(c);
        if(cnt==0)printf("0\n");
        else
        {
            for(ans=1;;ans++)
            {
                if(dfs(0))break;    
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
poj4007

14、bzoj1085: [SCOI2005]骑士精神

posted @ 2018-07-14 15:57  AKCqhzdy  阅读(392)  评论(0编辑  收藏  举报