| input | output |
|---|---|
4 0011 0110 |
22121112 |
4 1100 1100 |
Impossible |
题意:
给你两堆牌,牌的颜色只有红色或者黑色。 然后从两堆牌的牌顶来抽牌,每次抽可以选择两堆中的一堆。每次抽完,所得到的牌,红牌和黑牌数量相差必须不超过1。
做法:
因为一共各1000张牌,所以可以dp记忆化搜索。dp[i][j]代表 在第一堆牌抽了i张,第二堆牌抽了j张的情况下, 有没有不违反规则 达到这状态的方法。如果有 dp[i][j]会等于0,1,2,0表示当前多了一个黑牌,1表示当前红黑牌一样多,2表示当前红牌多一张。-2表示没达到这种状态的方法。
然后就是几种转移的方法,都要在dfs(i-1,j)或者 dfs(j,i-1) 可以达到的情况下 才能转移。
int dp[1100][1100];//
int n;
int num1[1100];
int num2[1100];
int bu[1100];
int dfs(int i,int j)
{
if(~dp[i][j])//不是-1,就返回已经有的值, 记忆化搜索,不然会超时
return dp[i][j];
if(i==0&&j==0)
return dp[i][j]=1;//0 0多 1平 2 1多
if(i!=0)
{
if(dfs(i-1,j)==0&&num1[i]==1)//这里表示,上一个状态 红黑牌中 红牌多,所以这次必须抽黑牌才能转移
{
bu[i+j]=1;
return dp[i][j]=1;
}
if(dfs(i-1,j)==1)
{
if(num1[i]==1)
{
bu[i+j]=1;
return dp[i][j]=2;
}
if(num1[i]==0)
{
bu[i+j]=1;
return dp[i][j]=0;
}
}
if(dfs(i-1,j)==2&&num1[i]==0)
{
bu[i+j]=1;
return dp[i][j]=1;
}
}
if(j!=0)
{
if(dfs(i,j-1)==0&&num2[j]==1)
{
bu[i+j]=2;
return dp[i][j]=1;
}
if(dfs(i,j-1)==1)
{
if(num2[j]==1)
{
bu[i+j]=2;
return dp[i][j]=2;
}
if(num2[j]==0)
{
bu[i+j]=2;
return dp[i][j]=0;
}
}
if(dfs(i,j-1)==2&&num2[j]==0)
{
bu[i+j]=2;
return dp[i][j]=1;
}
}
return dp[i][j]=-2;
}
char n1[1100];
char n2[1100];
int main()
{
while(scanf("%d",&n)!=EOF)
{
scanf("%s%s",n1,n2);
memset(dp,-1,sizeof dp);
for(int i=1;i<=n;i++)
{
num1[i]=n1[i-1]-'0';
num2[i]=n2[i-1]-'0';
}
if(dfs(n,n)!=-2)
{
for(int i=1;i<=2*n;i++)
printf("%d",bu[i]);
puts("");
}
else
puts("Impossible");
}
return 0;
}
原文地址:http://blog.csdn.net/u013532224/article/details/44698539