这两天把bfs的练习和八数码问题干完了,中间有一点小小的卡顿——康托展开。。。由于他给的计算公式和他在代码上的应用有点出入(个人理解,如果没有出入,那只能说明在下是个垃圾。。。)使我看了好久,都看烦了,甚至开始怀疑起了智商,最后才有了一点门道。
long int fact[]={1,1,2,6,24,120,720,5040,40320,362880};
bool cantor(int str[],int n){
long int result=0;
for(int i=0;i<n;i++){
int counted=0;
for(int j=i+1;j<n;j++){
if(str[i]>str[j])
counted++;
}//计算该元素在未出现的元素(也就是位于其后面的元素)中排第几个
result+=counted*fact[n-i-1];
}//计算这是第几个排列,这个地方fact[]里面的n-i-1以及
//上面的那一步刚好和书上的公式相反,书上的是a[i]与fact[i-1]对应
//而代码则是a[i]与fact[n-i-1]对应,这可能是由于计算公式与代码中的i
//定义不一样导致
八数码的A*算法(7.26补充)
int cal(int s[],int n){
int res=0;
for(int i=0;i<n;i++){
int x=i/3,y=i%3;
if(s[i]==0)
res+=(abs(x-2)+abs(y-2));
else{
int w=s[i]-1;
res+=(abs(x-w/3)+abs(y-w%3));
}
}
return res;
}
poj3126
http://poj.org/problem?id=3126
去网上搜题解,都说是一个简单搜索,但我觉得好难(吐血)。其实思路感觉不是很难,我也想出来了,但是难在我不会实现啊。。。素数打表我还可以应付,但这个搜的入口有点多,而且搜的条件我也不知道该怎么弄,让一个四位数每一位都改变一下再判断实在是有亿点难。。。看了一个大佬的,脑子还是有点生疏,等有空再回来看看。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#define ll long long
#define CHECK(x,y,z) (x>=0&&x<a&&y>=0&&y<b&&z>=0&&z<c&&!(vis[x][y][z])&&val[x][y][z])
//#include<bits/stdc++.h>
using namespace std;
int prime[10005];
int vis[10000],cnt=1;
bool isprime[10005];
typedef struct{
string s;
int step;
}num;
void dabiao(){//素数打表
isprime[0]=isprime[1]=1;
for(int i=2;i<=10000;i++) isprime[i]=1;
for(int i=2;i<=10000;i++){
if(isprime[i]) prime[cnt++]=i;
for(int j=1;j<cnt&&prime[j]*i<=10000;j++){
isprime[prime[j]*i]=0;
if(i%prime[j]==0)
break;
}
}
}
int s_int(string s){//将字符串转化为数字
int ret=0;
for(int i=0;i<4;i++){
ret*=10;
ret+=(s[i]-'0');
}
return ret;
}
int bfs(string a,string b){
queue<num>q;
num start;
start.s=a;
start.step=0;
q.push(start);
while(!q.empty()){
num temp=q.front();
q.pop();
if(b.compare(temp.s)==0)
return temp.step;
for(int i=0;i<4;i++){
for(int j=0;j<10;j++){
if(i==0&&j==0) continue;
num t=temp;
t.step++;
t.s[i]=j+'0';//实现改变四位数的单独一位
int cmp=s_int(t.s);
if(!vis[cmp]&&isprime[cmp]==1){
vis[cmp]=1;
q.push(t);//符合条件标记入队
}
}
}
}
}
int main(){
int n;
// freopen("in.txt","r",stdin);
dabiao();
cin>>n;
while(n--){
memset(vis,0,sizeof(vis));
string a,b;
cin>>a>>b;
int ans=bfs(a,b);
cout<<ans<<endl;
}
return 0;
}
poj3414
这个题的难点是入口多、情况多(多的我抄都快抄吐了。。。),而且还要打印路径,用回溯也可以做,等学完回溯再回来看看,这是bfs习题的最后一道,做完之后我发现难得不在于思路,而在于如何去实现思路,在这一点上还差很多,需要大量的练习。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#define ll long long
#define CHECK(x,y,z) (x>=0&&x<a&&y>=0&&y<b&&z>=0&&z<c&&!(vis[x][y][z])&&val[x][y][z])
//#include<bits/stdc++.h>
using namespace std;
bool vis[110][110];
struct Node{
int x,y;
int step;
int fa;int my;int flag;//my和fa是标记路径的,flag是判断哪一个操作
}node[10010];
queue<Node>q;
void path(int u){//打印路径
if(node[u].fa==-1)
return;
path(node[u].fa);
if(node[u].flag==11)
printf("FILL(1)\n");
else if(node[u].flag==12)
printf("FILL(2)\n");
else if(node[u].flag==21)
printf("DROP(1)\n");
else if(node[u].flag==22)
printf("DROP(2)\n");
else if(node[u].flag==31)
printf("POUR(1,2)\n");
else if(node[u].flag==32)
printf("POUR(2,1)\n");
}
int main(){
// freopen("in.txt","r",stdin);
int a,b,c,cnt;
scanf("%d%d%d",&a,&b,&c);
memset(vis,false,sizeof(vis));
vis[0][0]=true;
cnt=0;
node[cnt].x=0,node[cnt].y=0,node[cnt].step=0,node[cnt].fa=-1,node[cnt].my=0;
cnt++;
q.push(node[0]);
Node t;
while(!q.empty()){
t=q.front();
if(t.x==c||t.y==c)
break;
q.pop();
if(t.x<a&&!vis[a][t.y]){
vis[a][t.y]=true;
node[cnt].x=a,node[cnt].y=t.y,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=11;
q.push(node[cnt]);
cnt++;
}
if(t.y<b&&!vis[t.x][b]){
vis[t.x][b]=true;
node[cnt].x=t.x,node[cnt].y=b,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=12;
q.push(node[cnt]);
cnt++;
}
if(t.x>0&&!vis[0][t.y]){
vis[0][t.y]=true;
node[cnt].x=0,node[cnt].y=t.y,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=21;
q.push(node[cnt]);
cnt++;
}
if(t.y>0&&!vis[t.x][0]){
vis[t.x][0]=true;
node[cnt].x=t.x,node[cnt].y=0,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=22;
q.push(node[cnt]);
cnt++;
}
if(t.x>0&&t.y<b){
if(t.x>=b-t.y&&!vis[t.x-b+t.y][b]){
vis[t.x-b+t.y][b]=true;
node[cnt].x=t.x-b+t.y,node[cnt].y=b,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=31;
q.push(node[cnt]);
cnt++;
}
else if(t.x<b-t.y&&!vis[0][t.y+t.x]){
vis[0][t.y+t.x]=true;
node[cnt].x=0,node[cnt].y=t.x+t.y,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=31;
q.push(node[cnt]);
cnt++;
}
}
if(t.x<a&&t.y>0){
if(t.y>=a-t.x&&!vis[a][t.y-a+t.x]){
vis[a][t.y-a+t.x]=true;
node[cnt].x=a,node[cnt].y=t.y-a+t.x,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=32;
q.push(node[cnt]);
cnt++;
}
else if(t.y<a-t.x&&!vis[t.x+t.y][0]){
vis[t.y+t.x][0]=true;
node[cnt].x=t.x+t.y,node[cnt].y=0,node[cnt].step=t.step+1,node[cnt].my=cnt,node[cnt].fa=t.my,node[cnt].flag=32;
q.push(node[cnt]);
cnt++;
}
}
}
if(q.empty()) printf("impossible\n");
else{
printf("%d\n",t.step);
path(t.my);
}
return 0;
}
8.16回来补上dfs的代码(虽然还是看的题解,无能的我。。。)
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<iomanip>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<list>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y) (x>=0&&x<H&&y>=0&&y<W&&vis[x][y]==0)
//#include<bits/stdc++.h>
using namespace std;
const ll maxx=1e9;
int dir[4][3]={
{-1,0},
{1,0},
{0,-1},
{0,1},
};
int vis[110][110],endd,a,b,c;
char option[][10]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(2,1)","POUR(1,2)"},s[2050][15],s2[2050][15];
void dfs(int x,int y,int cnt){
if(cnt>=endd) return;
if(x==c||y==c){
endd=cnt;
for(int i=0;i<endd;i++)
strcpy(s2[i],s[i]);
}
strcpy(s[cnt],option[0]);
if(!vis[a][y]){
vis[a][y]=1;
dfs(a,y,cnt+1);
vis[a][y]=0;
}
strcpy(s[cnt],option[1]);
if(!vis[x][b]){
vis[x][b]=1;
dfs(x,b,cnt+1);
vis[x][b]=0;
}
strcpy(s[cnt],option[2]);
if(!vis[0][y]){
vis[0][y]=1;
dfs(0,y,cnt+1);
vis[0][y]=0;
}
strcpy(s[cnt],option[3]);
if(!vis[x][0]){
vis[x][0]=1;
dfs(x,0,cnt+1);
vis[x][0]=0;
}
strcpy(s[cnt],option[4]);
if(x<a&&y>0){
if(x+y<=a&&!vis[x+y][0]){
vis[x+y][0]=1;
dfs(x+y,0,cnt+1);
vis[x+y][0]=0;
}
else if(x+y>a&&!vis[a][y-a+x]){
vis[a][y-a+x]=1;
dfs(a,y-a+x,cnt+1);
vis[a][y-a+x]=0;
}
}
strcpy(s[cnt],option[5]);
if(y<b&&x>0){
if(x+y<=b&&!vis[0][x+y]){
vis[0][x+y]=1;
dfs(0,x+y,cnt+1);
vis[0][x+y]=0;
}
else if(x+y>b&&!vis[x-b+y][b]){
vis[x-b+y][b]=1;
dfs(x-b+y,b,cnt+1);
vis[x-b+y][b]=0;
}
}
}
int main(){
// freopen("in.txt","r",stdin);
cin>>a>>b>>c;
endd=1000000;
dfs(0,0,0);
if(endd==1000000) cout<<"impossible"<<endl;
else {
cout<<endd<<endl;
for(int i=0;i<endd;i++){
cout<<s2[i]<<endl;
}
}
return 0;
}
poj1077(八数码问题)
这个题的难点是打印路径,其他的和书上的八数码没有多大区别,还好上一次碰到过打印路径的题,这次就直接拿过来用了,没想到还真是成了,我测了测程序运行也就0.03s,但c++就是说我超时,最后在g++上AC了。
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y,z) (x>=0&&x<a&&y>=0&&y<b&&z>=0&&z<c&&!(vis[x][y][z])&&val[x][y][z])
//#include<bits/stdc++.h>
using namespace std;
struct Node{
int state[9];
int fa;int my;int flag;//my和fa是标记路径的,flag是判断哪一个操作
}node[362885];
int dir[5][5]={{-1,0},{0,-1},{1,0},{0,1}};
int vis[362885]={0};
long int fact[]={1,1,2,6,24,120,720,5040,40320,362880};
bool cantor(int str[],int n){
long int result=0;
for(int i=0;i<n;i++){
int counted=0;
for(int j=i+1;j<n;j++){
if(str[i]>str[j])
counted++;
}
result+=counted*fact[n-i-1];
}
if(!vis[result]){
vis[result]=1;
return true;
}
else return false;
}
queue<Node>q;
void path(int u){//打印路径
if(node[u].fa==-1)
return;
path(node[u].fa);
if(node[u].flag==0)
printf("l");
else if(node[u].flag==1)
printf("u");
else if(node[u].flag==2)
printf("r");
else if(node[u].flag==3)
printf("d");
}
int main(){
// freopen("in.txt","r",stdin);
char start1[9];
int goal[9],start[9],cnt=0;
for(int i=0;i<8;i++){
goal[i]=i+1;
}
goal[8]=0;
for(int i=0;i<9;i++){
scanf("%s",&start1[i]);
if(start1[i]=='x') start1[i]='0';
}
// clock_t kaishi,jieshu;
//kaishi=clock();
for(int i=0;i<9;i++) start[i]=start1[i]-'0';
Node head;
memcpy(node[0].state,start,sizeof(node[0].state));
cantor(node[0].state,9); cnt++; q.push(node[0]);
node[0].fa=-1; node[0].my=0;
while(!q.empty()){
head=q.front();
if(memcmp(head.state,goal,sizeof(goal))==0)
break;
q.pop();
int z=0;
for(z=0;z<9;z++) if(head.state[z]==0) break;
int x=z%3; int y=z/3;
for(int i=0;i<4;i++){
int newx=x+dir[i][0];
int newy=y+dir[i][1];
int nz=newx+3*newy;
if(newx>=0&&newx<3&&newy>=0&&newy<3){
memcpy(&node[cnt],&head,sizeof(node[cnt]));
swap(node[cnt].state[z],node[cnt].state[nz]);
if(cantor(node[cnt].state,9)){
node[cnt].my=cnt,node[cnt].fa=head.my,node[cnt].flag=i;
q.push(node[cnt]);
cnt++;
}
}
}
}
if(q.empty()) printf("unsolvable\n");
else{
path(head.my);
}
/* jieshu=clock();
cout<<endl;
cout<<(double)(jieshu-kaishi)/CLOCKS_PER_SEC<<endl;*/
return 0;
}
学的A*算法就用A*做了一遍,没想到连以前过不了的c++也过了,还真是个优化算法。一开始想看别人是怎么打的,但实在是看不下去,整体的代码就不一样,看的又烦又想吐,最后知道怎么打A*算法后在自己的代码上改了改,没想到AC了。哎,不要轻易的就认为别人的代码比自己的代码好啊!
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<cstdio>
#include<map>
#include<cmath>
#include<vector>
#include<queue>
#include<list>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define CHECK(x,y,z) (x>=0&&x<a&&y>=0&&y<b&&z>=0&&z<c&&!(vis[x][y][z])&&val[x][y][z])
//#include<bits/stdc++.h>
using namespace std;
struct Node{
int state[9];int g,h;
int fa;int my;int flag;//my和fa是标记路径的,flag是判断哪一个操作
friend bool operator<(Node a,Node b){
return a.g+a.h>b.g+b.h;
}
}node[362885];
int dir[5][5]={{-1,0},{0,-1},{1,0},{0,1}};
int vis[362885]={0};
long int fact[]={1,1,2,6,24,120,720,5040,40320,362880};
bool cantor(int str[],int n){
long int result=0;
for(int i=0;i<n;i++){
int counted=0;
for(int j=i+1;j<n;j++){
if(str[i]>str[j])
counted++;
}
result+=counted*fact[n-i-1];
}
if(!vis[result]){
vis[result]=1;
return true;
}
else return false;
}
int cal(int s[],int n){
int res=0;
for(int i=0;i<n;i++){
int x=i/3,y=i%3;
if(s[i]==0)
res+=(abs(x-2)+abs(y-2));
else{
int w=s[i]-1;
res+=(abs(x-w/3)+abs(y-w%3));
}
}
return res;
}
priority_queue<Node>q;
void path(int u){//打印路径
if(node[u].fa==-1)
return;
path(node[u].fa);
if(node[u].flag==0)
printf("l");
else if(node[u].flag==1)
printf("u");
else if(node[u].flag==2)
printf("r");
else if(node[u].flag==3)
printf("d");
}
int main(){
// freopen("in.txt","r",stdin);
char start1[9];
int goal[9],start[9],cnt=0;
for(int i=0;i<8;i++){
goal[i]=i+1;
}
goal[8]=0;
for(int i=0;i<9;i++){
scanf("%s",&start1[i]);
if(start1[i]=='x') start1[i]='0';
}
//clock_t kaishi,jieshu;
// kaishi=clock();
for(int i=0;i<9;i++) start[i]=start1[i]-'0';
Node head;
memcpy(node[0].state,start,sizeof(node[0].state));
cantor(node[0].state,9); cnt++;
node[0].fa=-1; node[0].my=0;node[0].g=0;q.push(node[0]);
while(!q.empty()){
head=q.top();
if(memcmp(head.state,goal,sizeof(goal))==0)
break;
q.pop();
int z=0;
for(z=0;z<9;z++) if(head.state[z]==0) break;
int x=z%3; int y=z/3;
for(int i=0;i<4;i++){
int newx=x+dir[i][0];
int newy=y+dir[i][1];
int nz=newx+3*newy;
if(newx>=0&&newx<3&&newy>=0&&newy<3){
memcpy(&node[cnt],&head,sizeof(node[cnt]));
swap(node[cnt].state[z],node[cnt].state[nz]);
node[cnt].g++;
if(cantor(node[cnt].state,9)){
node[cnt].my=cnt,node[cnt].fa=head.my,node[cnt].flag=i;node[cnt].h=cal(node[cnt].state,9);
q.push(node[cnt]);
cnt++;
}
}
}
}
if(q.empty()) printf("unsolvable\n");
else{
path(head.my);
}
/* jieshu=clock();
cout<<endl;
cout<<(double)(jieshu-kaishi)/CLOCKS_PER_SEC<<endl;*/
return 0;
}