1.题目描述:
2.题意:
给你两个01序列,希望你生成一个01序列,使得其在生成过程中,01的差值不超过1。输出可能的选择顺序【任意一个】,或者“Impossible”。
3.思路:
dfs+记忆化。
1)暴力dfs+记忆化路线剪枝。
记录下选择的左右堆以及选择的0和1的个数,碰到重复走的路之间剪枝掉。
部分代码:
int n,m;
char a[maxn],b[maxn];
int tot;
int ans[maxn<<1];
int dp[maxn][maxn];
bool flag;
void dfs(int cnta,int cntb,int one,int zero)
{
if(cnta==n&&cntb==n) {flag=1;return;}
if(!dp[cnta][cntb]) dp[cnta][cntb]=1;
else return;
if(cnta!=n)
{
if(one==zero)
{
ans[tot++]=1;
if(a[cnta]=='0')
{
if(dfs(cnta+1,cntb,one,zero+1),flag) return;
}
else
{
if(dfs(cnta+1,cntb,one+1,zero),flag) return;
}
tot--;
}
else if(one<zero&&a[cnta]=='1')
{
ans[tot++]=1;
if(dfs(cnta+1,cntb,one+1,zero),flag) return;
tot--;
}
else if(zero<one&&a[cnta]=='0')
{
ans[tot++]=1;
if(dfs(cnta+1,cntb,one,zero+1),flag) return;
tot--;
}
}
if(cntb!=n)
{
if(one==zero)
{
ans[tot++]=2;
if(b[cntb]=='0')
{
if(dfs(cnta,cntb+1,one,zero+1),flag) return;
}
else
{
if(dfs(cnta,cntb+1,one+1,zero),flag) return;
}
tot--;
}
else if(one<zero&&b[cntb]=='1')
{
ans[tot++]=2;
if(dfs(cnta,cntb+1,one+1,zero),flag) return;
tot--;
}
else if(zero<one&&b[cntb]=='0')
{
ans[tot++]=2;
if(dfs(cnta,cntb+1,one,zero+1),flag) return;
tot--;
}
}
}
li void solve()
{
scanf("%s",a);
scanf("%s",b);
tot=0;flag=0;
dfs(0,0,0,0);
if(!flag) puts("Impossible");
else {rep(i,0,tot) printf("%d",ans[i]);puts("");}
}
int main()
{
//FAST;
//srand(time(0));
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
//for(int QwQ=read();QwQ;QwQ--) solve();
while(~scanf("%d",&n)) solve();
return 0;
}
2)合并操作+记忆化路线剪枝。
我们可以分类讨论一下可能的情况:
a)如果一堆的最上面两张是相异的,我们就可以直接拿走了。
b)如果两堆的最上面一张是相异的,我们也可以直接拿走了。
递归重复这两种情况,然后分别在路径上输出结果就OK了。
部分代码:
int n,m;
char a[maxn],b[maxn];
int dp[maxn][maxn];
int dfs(int x,int y)
{
if(!x&&!y) return true;
if(!dp[x][y]) dp[x][y]=true;
else return false;
if(x>=2&&a[x]!=a[x-1]&&dfs(x-2,y)){printf("11");return true;}
if(y>=2&&b[y]!=b[y-1]&&dfs(x,y-2)){printf("22");return true;}
if(x&&y&&a[x]!=b[y]&&dfs(x-1,y-1)){printf("12");return true;}
return false;
}
li void solve()
{
scanf("%s%s",a+1,b+1);
if(!dfs(n,n)) puts("Impossible");
else puts("");
}
int main()
{
//FAST;
//srand(time(0));
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
//for(int QwQ=read();QwQ;QwQ--) solve();
while(~scanf("%d",&n)) solve();
return 0;
}
3)dfs+dp剪枝
这个是存储状态来剪枝的。我们把前面一个状态保留下来,用于判断现在这个状态如何。
dp[i][j]就意味着,前面一堆选i个,后面一堆选j个。
dp的值:
-2:代表这个状态不能得到正确的解。
-1:初始值
0:上一状态0和1的数量相同。
1:0比1多
2:1比0多
部分代码:
int n,m;
char a[maxn],b[maxn];
int ans[maxn<<1];
int dp[maxn][maxn];//-2:失败,0:一样多,1:0多,2:1多
int dfs(int x,int y)
{
if(~dp[x][y]) return dp[x][y];
if(!x&&!y) return dp[x][y]=0;
if(x)
{
if(dfs(x-1,y)==0)
{
ans[x+y]=1;
if(a[x]=='0') return dp[x][y]=1;
else return dp[x][y]=2;
}
if(dfs(x-1,y)==1&&a[x]=='1'){ans[x+y]=1;return dp[x][y]=0;}
if(dfs(x-1,y)==2&&a[x]=='0'){ans[x+y]=1;return dp[x][y]=0;}
}
if(y)
{
if(dfs(x,y-1)==0)
{
ans[x+y]=2;
if(b[y]=='0') return dp[x][y]=1;
else return dp[x][y]=2;
}
if(dfs(x,y-1)==1&&b[y]=='1'){ans[x+y]=2;return dp[x][y]=0;}
if(dfs(x,y-1)==2&&b[y]=='0'){ans[x+y]=2;return dp[x][y]=0;}
}
return dp[x][y]=-2;
}
li void solve()
{
mem(dp,-1);
mem(ans,0);
scanf("%s",a+1);
scanf("%s",b+1);
if(dfs(n,n)==-2) puts("Impossible");
else {rep(i,1,(n<<1)+1) printf("%d",ans[i]);puts("");}
}
int main()
{
//FAST;
//srand(time(0));
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
//for(int QwQ=read();QwQ;QwQ--) solve();
while(~scanf("%d",&n)) solve();
return 0;
}