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