CSU 1536 Bit String Reordering(BFS)
1536: Bit String Reordering
Time Limit: 1 Sec Memory Limit: 256 MBSubmit: 129 Solved: 45
[Submit][Status][Web Board]
Description
Input
Output
Sample Input
6 3
1 0 0 1 0 1
1 3 2
Sample Output
1
HINT
Source
这道题当时比赛的时候是用贪心+模拟做的= =
后来出来听他们说可以状压+BFS做,回来敲一下就1A了
状压+BFS(),就是把每次变化的01串变成一个数字,然后每次交换相邻的两个位置,知道找到最后的结果就输出最小步数
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<ctype.h> #include<cstring> #include<stdlib.h> #include<algorithm> using namespace std; const int MAXN=20; int n,m,result; int a[MAXN],temp[MAXN],b[MAXN],vis[1000000]; struct node { int res;//01串代表的数字 int step;//步数 int num[MAXN];//01串 }s1,s2; queue<node> Q; int calc(int num[]) { int ans=0,ok=1; for(int i=n-1;i>=0;i--) { ans+=ok*num[i]; ok*=2; } return ans; } int BFS() { node now,next; while(!Q.empty()) { now=Q.front(); Q.pop(); if(now.res==result) return now.step; for(int i=0;i<n;i++) next.num[i]=now.num[i]; for(int i=0;i<n-1;i++) { swap(next.num[i],next.num[i+1]);//交换相邻的两位生成新的01串 next.res=calc(next.num); if(!vis[next.res]) { vis[next.res]=1; next.step=now.step+1; Q.push(next); } swap(next.num[i],next.num[i+1]); } } } int main() { scanf("%d %d",&n,&m); for(int i=0;i<n;i++) scanf("%d",&a[i]); for(int i=0;i<m;i++) scanf("%d",&temp[i]); int cnt=0,flag=1; for(int i=0;i<m;i++) { for(int j=0;j<temp[i];j++) s1.num[cnt++]=flag; flag=!flag; } s1.res=calc(s1.num); s1.step=0; Q.push(s1); vis[s1.res]=1;//初始化第一个起点串信息 cnt=0,flag=0; for(int i=0;i<m;i++) { for(int j=0;j<temp[i];j++) s2.num[cnt++]=flag; flag=!flag; } s2.res=calc(s2.num); s2.step=0; Q.push(s2); vis[s2.res]=1;//初始化第二个起点串信息 result=calc(a); int ans=BFS(); printf("%d\n",ans); return 0; }
贪心+模拟,就是先生成两个起点01串,然后每次把起点01串和终点01串对比一下,如果发现在相对应的位置的数字不相同的话,就往后找出第一个不相同的数字(比如当前起点串为0终点串为1,那么起点串就要往后面找出第一个1)然后加上两个位置的差距,再比较下一位。 听起来很复杂= =,但是很多代码都是相同的
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<stdlib.h> #include<algorithm> using namespace std; const int MAXN=20; int a[MAXN],b[MAXN],num[MAXN],temp[MAXN],ans; void swap(int &a,int &b) { int temp; temp=a; a=b; b=temp; } int min(int a,int b) { if(a>b) return b; else return a; } int main() { int n,m,num0=0,num1=0,res1=0,res2=0; int minn=0x3f3f3f3f; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(a[i]==1) num1++; if(a[i]==0) num0++; }//分别统计终点串01出现的次数 for(int i=1;i<=m;i++) { scanf("%d",&temp[i]); if(i%2==1) res1+=temp[i]; if(i%2==0) res2+=temp[i]; }//这样加的目的是判断起点串第一个数字是放0还是1 if(res1==num1) { ans=0; memset(b,0,sizeof(b)); for(int i=1;i<=n;i++) num[i]=a[i]; int flag=1,cnt=1; for(int i=1;i<=m;i++) { for(int j=1;j<=temp[i];j++) b[cnt++]=flag; flag=!flag; }//生成起点串 for(int i=1;i<=n;i++) { if(num[i]==b[i]) continue; else { for(int j=i+1;j<=n;j++) { if(b[j]==!b[i]) { swap(b[j],b[i]); ans+=j-i; break; } } } }//贪心找出最近的一个取反位然后加上距离 minn=min(ans,minn); } if(res1==num0) { ans=0; memset(b,0,sizeof(b)); for(int i=1;i<=n;i++) num[i]=a[i]; int flag=0,cnt=1; for(int i=1;i<=m;i++) { for(int j=1;j<=temp[i];j++) b[cnt++]=flag; flag=!flag; } for(int i=1;i<=n;i++) { if(num[i]==b[i]) continue; else { for(int j=i+1;j<=n;j++) { if(b[j]==!b[i]) { swap(b[j],b[i]); ans+=j-i; break; } } } } minn=min(ans,minn); } printf("%d\n",minn); return 0; }