五月份做的吧 那个时候用了dp 死活过不了 后来听人说dp是可行的 但我还是不会,囧。。。这题用了比较快的广搜算法,用v[i][j][k]存储余数从i->j,去掉数字为k的情况,由于状态空间<1000,所以穷搜状态空间是可行的。这题具体来说可以分成三种情况:
1.字符串中既没有5也没有0,那么可以直接impossble掉
2.如果字符串中有5但是没有0,可以先去掉一个5,然后在穷搜,最后在末尾添加上。
3.其他情况,只要有0,末尾一定是0。
代码如下:
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
struct node
{
int num[10];
int r;
}q[1010];
int getd(int num[])//统计这个大数的位数
{
int ans=0;
for(int i=0;i<10;i++)
{
ans+=num[i];
}
return ans;
}
int getsum(int num[])//统计这个大数每位之和
{
int ans=0;
for(int i=0;i<10;i++)
{
ans+=num[i]*i;
}
return ans;
}
int v[11][11][11];//hash判重
int num[10];//初始大数
int flagnum[10];
char s[2000];//字符串
int t;
bool haszero;//有0吗?
bool hasfive;//有5吗?
int ansnum[10];//最终结果,有中间处理,注意加0加5的情况
int ansflag;
int cmp(int ansnum[],int num[])
{
int len1=getd(ansnum);
int len2=getd(num);
//特别处理一下两个数是全0的情况
if(getsum(ansnum)==0&&getsum(num)==0)
return 0;
else if(getsum(ansnum)==0&&getsum(num)!=0)
return -1;
else if(getsum(ansnum)!=0&&getsum(num)==0)
return 1;
//end
if(len1>len2)
return 1;
else if(len1<len2)
return -1;
else
{
int i;
for(i=9;i>=1;i--)
{
if(ansnum[i]>num[i])
return 1;
else if(ansnum[i]<num[i])
return -1;
}
return 0;
}
}
void copy(int t[],int s[])//copy s里面的东西到t
{
int i;
for(i=0;i<=9;i++)
t[i]=s[i];
}
void input()//从1开始存储
{
ansflag=0;
hasfive=haszero=0;
scanf("%s",s+1);
memset(ansnum,0,sizeof(ansnum));
memset(num,0,sizeof(num));
memset(v,0,sizeof(v));
int i;
int len=strlen(s+1);
for(i=1;i<=len;i++)
{
int tt=(s[i]-'0');
num[tt]++;
if(tt==0)
haszero=1;
if(tt==5)
hasfive=1;
}
}
void output(int num[])//没有加回车,注意预先去掉的数字
{
for(int i=9;i>=0;i--)
{
if(num[i]!=0)
for(int j=1;j<=num[i];j++)
printf("%d",i);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
input();
if(!haszero&&!hasfive)
{
printf("impossible\n");
continue;
}
/**//*
if(haszero&&!hasfive)
{
int l,r;
l=r=1;
copy(q[1].num,num);
int tem=getsum(q[1].num);
tem%=9;
q[1].r=tem%9;
v[tem][tem][0]=1;
while(l<=r)
{
if(cmp(q[l].num,ansnum)==1&&q[l].r==0)
{
ansflag=1;
copy(ansnum,q[l].num);
}
for(int i=1;i<10;i++)
{
int nr=(q[l].r-i+9)%9;
if(q[l].num[i]>0&&v[q[l].r][nr][i]==0)
{
r++;
copy(q[r].num,q[l].num);
q[r].num[i]--;
q[r].r=nr;
v[q[l].r][nr][i]=1;
}
}
l++;
}
if(ansflag==1)
{
output(ansnum);
printf("\n");
}
else
printf("0\n");
}
*/
else if(!haszero&&hasfive)//没有0但是有5
{
int l,r;
l=r=1;
copy(q[1].num,num);
q[1].num[5]--;
int tem=getsum(q[1].num);
q[1].r=tem%9;
tem%=9;
v[tem][tem][0]=1;
while(l<=r)
{
if(cmp(q[l].num,ansnum)==1&&q[l].r==4)
{
ansflag=1;
copy(ansnum,q[l].num);
}
for(int i=1;i<10;i++)
{
/**//*
if(i==5)
{
__asm
{
int 3;
}
}
*/
int nr=(q[l].r-i+9)%9;
if(q[l].num[i]>0&&v[q[l].r][nr][i]==0)
{
r++;
copy(q[r].num,q[l].num);
q[r].num[i]--;
q[r].r=nr;
v[q[l].r][nr][i]=1;
}
}
l++;
}
if(ansflag==1)
{
output(ansnum);
printf("5\n");
}
else
printf("impossible\n");
}
else //没有0但是有5或者有0有5,情况相同
{
int l,r;
l=r=1;
copy(q[1].num,num);
int tem=getsum(q[1].num);
tem%=9;
q[1].r=tem%9;
v[tem][tem][0]=1;
while(l<=r)
{
if(cmp(q[l].num,ansnum)==1&&q[l].r==0)
{
ansflag=1;
copy(ansnum,q[l].num);
}
for(int i=1;i<10;i++)
{
int nr=(q[l].r-i+9)%9;
if(q[l].num[i]>0&&v[q[l].r][nr][i]==0)
{
r++;
copy(q[r].num,q[l].num);
q[r].num[i]--;
q[r].r=nr;
v[q[l].r][nr][i]=1;
}
}
l++;
}
if(ansflag==1)
{
output(ansnum);
printf("\n");
}
else
printf("0\n");
}
}
return 0;
}
代码写的比较长比较猥琐,不知道能把几个广搜合并下么。
感谢messidou神牛指点。