24 条题解
-
0Yolla LV 8 @ 2015-11-25 17:23:16
此程序在UOj和洛谷都过了;
在这卡了一个点
不要问我怎么做
我只提供程序(不是我写的)
搞不懂为什么 -
02015-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;
} -
02015-11-14 19:06:58@
看到2S和1G的内存就写了DFS= =但是没考虑要先出顺子更优秀。作死先打了四带二什么的,30%的数据以上就有点卡......估计只有30分了。。。
大牛说先打顺子似乎可以过
还听说有记忆化搜索+哈希还有BFS+哈希啊之类。当然也有说DFS的。总之正解应该就在这三种算法了。可能都对,也可能只是其中几个吧////
-
-12015-11-17 21:57:30@
先DP预处理出有a张单牌,b张对牌,c张三张,d张炸弹时不用顺子需要出的最少次数
(贪心好像有问题,炸弹带炸弹什么的最讨厌了)
转移方程?呵呵呵……自己手推吧然后DFS顺子,再用预处理的结果出解,方便好写……而且跑的快
实测t=10000 n=23都能卡进2秒……
代码不超过100行。
信息
- ID
- 1980
- 难度
- 8
- 分类
- (无)
- 标签
- 递交数
- 2591
- 已通过
- 352
- 通过率
- 14%
- 被复制
- 12
- 上传者