题解

24 条题解

  • 0
    @ 2015-11-25 17:23:16

    此程序在UOj和洛谷都过了;
    在这卡了一个点
    不要问我怎么做
    我只提供程序(不是我写的)
    搞不懂为什么

    • @ 2015-11-26 13:32:34

      实测发现,在那个点,双王被当成对子,被三带二或四带对搞掉了;强制双王单独出后可AC

  • 0
    @ 2015-11-22 21:08:36

    这道题有毒啊!!!一直有两个点被卡!!!我不想改了啊!!!!(官网数据过了,为什么考试的时候肾虚没码出来啊!!!)
    你问我做法?bfs+hash判重,注意一个显然的剪枝,注意到单独出牌是一种无可奈何的举动(先单独打不是最优解),只有在无法用其他方式出牌时一次性处理即可。
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    using std::queue;
    bool vis1[1300001],vis2[560214];
    int prime[14]={19,89,433,3259,7013,10259,7187,203,991,5107,56821,47369,59881,2169};
    int rank[14]={293,337,59,61,11,9433,12703,6113,5333,27409,221,9293,2081,7843};
    struct puck{
    int num[15];
    void clear()
    {memset(num,0,sizeof(num));}
    };
    int hash1(puck a)
    {
    int r=0;
    for(int i=0;i<=13;i++)
    r+=a.num[i]*prime[i];
    return r;
    }
    int hash2(puck a)
    {
    int r=0;
    for(int i=0;i<=13;i++)
    r+=a.num[i]*rank[i];
    return r;
    }
    struct st{
    int dis;
    puck a;
    };
    puck f;
    queue<st> q;
    int bfs()
    {
    memset(vis1,0,sizeof(vis1));
    memset(vis2,0,sizeof(vis2));
    vis1[hash1(f)]=vis2[hash2(f)]=1;
    st baka;
    bool fg;
    int ans(1<<29);
    q.push((st){0,f});
    int j;
    while(!q.empty())
    {
    fg=false;
    baka=q.front();
    q.pop();
    if(hash1(baka.a)==0)
    {
    // printf("%d ",baka.a.num[5]);
    ans=std::min(ans,baka.dis);
    continue;
    }
    for(int i=0;i<=13;i++)
    {
    if(baka.a.num[i]>=4)
    {
    fg=true;
    baka.a.num[i]-=4;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    for(int j=1;j<=13;j++)
    for(int k=j;k<=13;k++)
    if(j!=i && k!=i)
    {
    if((baka.a.num[j]>1 && baka.a.num[k]>1 && j!=k)||(j==k && baka.a.num[k]>=4))
    {
    baka.a.num[j]-=2;baka.a.num[k]-=2;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    baka.a.num[j]+=2;baka.a.num[k]+=2;
    }
    }
    for(int j=1;j<=13;j++)
    for(int k=j;k<=13;k++)
    {
    if((baka.a.num[j]>=1 && baka.a.num[k]>=1 && j!=k)||(j==k && baka.a.num[k]>=2))
    {
    baka.a.num[j]--;baka.a.num[k]--;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    baka.a.num[j]++;baka.a.num[k]++;
    }
    }
    baka.a.num[i]+=4;
    }
    if(baka.a.num[i]>=3 && i>0)
    {
    fg=true;
    baka.a.num[i]-=3;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    for(j=1;j<=13;j++)
    if(j!=i)
    {
    if(baka.a.num[j]>1 )
    {
    baka.a.num[j]-=2;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    baka.a.num[j]+=2;
    }
    }
    for(j=0;j<=13;j++)
    if(j!=i)
    {
    if(baka.a.num[j]>0 )
    {
    baka.a.num[j]--;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    baka.a.num[j]++;
    }
    }
    if(i>=2)
    for(j=i+1;baka.a.num[j]>=3 && j<=13;j++)
    {
    baka.a.num[j]-=3;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    }
    if(i>=2)
    for(int k=i+1; k<j;k++)
    baka.a.num[k]+=3;
    baka.a.num[i]+=3;
    }
    if(baka.a.num[i]>=2)
    {
    fg=true;
    baka.a.num[i]-=2;
    // printf("%d ",i);
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    if(i>=2)
    for(j=i+1;baka.a.num[j]>=2 && j<=13;j++)
    {
    baka.a.num[j]-=2;
    if(j>i+1)
    {
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    }
    }
    if(i>=2)
    for(int k=i+1;k<j;k++)
    baka.a.num[k]+=2;
    baka.a.num[i]+=2;
    }
    if(baka.a.num[i]>0 && i>=2 && i<10)
    {
    for(j=i;baka.a.num[j]>=1 && j<=13;j++)
    {
    baka.a.num[j]--;
    if(j-i>3)
    {
    fg=true;
    if(!vis1[hash1(baka.a)] || !vis2[hash2(baka.a)])
    {
    q.push((st){baka.dis+1,baka.a});
    vis1[hash1(baka.a)]=vis2[hash2(baka.a)]=1;
    }
    // printf("%d ",j);
    }
    }
    for(int k=i;k<j;k++)
    baka.a.num[k]++;
    }
    }
    if(!fg)
    {
    int cnt(0);
    for(int i=0;i<=13;i++)
    if(baka.a.num[i]>0)
    cnt++;
    ans=std::min(ans,baka.dis+cnt);
    }
    }
    return ans;
    }
    int main()
    {
    int t,n,a,b;
    int ans(0);
    // freopen("landlords.in","r",stdin);
    //freopen("landlords.out","w",stdout);
    scanf("%d%d",&t,&n);
    while(t--)
    {
    f.clear();
    for(int i=0;i<n;i++)
    {
    scanf("%d%d",&a,&b);
    if(a==1) f.num[13]++;
    else if(a==0) f.num[0]++;
    else f.num[a-1]++;
    }
    ans=bfs();
    printf("%d\n",ans);
    }
    return 0;
    }

  • 0
    @ 2015-11-14 19:06:58

    看到2S和1G的内存就写了DFS= =但是没考虑要先出顺子更优秀。作死先打了四带二什么的,30%的数据以上就有点卡......估计只有30分了。。。

    大牛说先打顺子似乎可以过

    还听说有记忆化搜索+哈希还有BFS+哈希啊之类。当然也有说DFS的。总之正解应该就在这三种算法了。可能都对,也可能只是其中几个吧////

  • -1
    @ 2015-11-17 21:57:30

    先DP预处理出有a张单牌,b张对牌,c张三张,d张炸弹时不用顺子需要出的最少次数
    (贪心好像有问题,炸弹带炸弹什么的最讨厌了)
    转移方程?呵呵呵……自己手推吧

    然后DFS顺子,再用预处理的结果出解,方便好写……而且跑的快

    实测t=10000 n=23都能卡进2秒……
    代码不超过100行。

信息

ID
1980
难度
8
分类
(无)
标签
递交数
2590
已通过
351
通过率
14%
被复制
12
上传者