89 条题解
-
3larryzhong LV 9 @ 2017-05-18 13:14:38
和 P1360 八数码问题 很像, 暴力广搜 + map 判重.
AC 代码:#include <iostream> #include <queue> #include <map> using namespace std; int dx[4] = {-1, 1, 0, 0}, dy[4] = {0, 0, -1, 1}; struct matrix { int arr[4][4]; bool operator < (const matrix &other) const { for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { if (arr[i][j] < other.arr[i][j]) return true; if (arr[i][j] > other.arr[i][j]) return false; } return false; } }; int main() { matrix start, _end; for (int i = 0; i < 4; i++) { string input; cin >> input; for (int j = 0; j < 4; j++) start.arr[i][j] = input[j] - '0'; } for (int i = 0; i < 4; i++) { string input; cin >> input; for (int j = 0; j < 4; j++) _end.arr[i][j] = input[j] - '0'; } queue<matrix> que; map<matrix, int> steps; que.push(start); steps[start] = 0; while (!que.empty() && steps.find(_end) == steps.end()) { matrix front = que.front(); que.pop(); for (int x0 = 0; x0 < 4; x0++) for (int y0 = 0; y0 < 4; y0++) for (int i = 0; i < 4; i++) { int x = x0 + dx[i]; int y = y0 + dy[i]; if (x >= 0 && x < 4 && y >= 0 && y < 4) { matrix push = front; swap(push.arr[x0][y0], push.arr[x][y]); if (steps.find(push) == steps.end()) { que.push(push); steps[push] = steps[front] + 1; } } } } cout << steps[_end] << endl; return 0; }
-
12021-01-03 16:57:43@
写了个相对清晰的题解= = 供参考
/** * 简单BFS+二进制即可 * * 顺便问问那些变量命名全部是a b c d u v、没一个注释还发到题解区的dalao们,你们的良心不会痛么 (= =) * * */ #include <stdio.h> #include <inttypes.h> #define QUEUE_MAX 200000 //取出num的第i位 #define get(num, i) (((num) >> (15 - (i)))&1) //返回第i位取反后的num #define flip(num, i) ((num) ^ (1 << (15 - (i)))) /* * 从第i位出发可交换的位置,-1表示不可交换 * 0 1 2 3 * 4 5 6 7 * 8 9 10 11 * 12 13 14 15 * */ int stepMap[16][2] = { {1, 4}, {2, 5}, {3, 6}, {7, -1}, {5, 8}, {6, 9}, {7, 10}, {11, -1}, {9, 12}, {10, 13}, {11, 14}, {15, -1}, {13, -1}, {14, -1}, {15, -1}, {-1, -1} }; //原队列中是否存在num uint_fast8_t contains(const uint_fast16_t queue[QUEUE_MAX][2], uint_fast16_t num, int tail) { for (int i = 0; i < tail; i++) { if (queue[i][0] == num)return 1; } return 0; } int main() { //queue中每个位置储存一个状态和一个行走步数;goal即为目标 uint_fast16_t queue[QUEUE_MAX][2] = {0}, goal = 0; int head = 0, tail = 1; char str[10]; //读入数据 for (int i = 0; i < 4; i++) { gets(str); for (int j = 0; j < 4; j++) { queue[0][0] += (str[j] - '0') << (15 - i * 4 - j); } } gets(str); for (int i = 0; i < 4; i++) { gets(str); for (int j = 0; j < 4; j++) { goal += (str[j] - '0') << (15 - i * 4 - j); } } //第二个测试点的起点即为答案 (= _ =) if (queue[0][0] == goal) { printf("0"); return 0; } //队列尚未结束 while (head < tail) { //依次考虑0-15位的交换 for (int i = 0; i < 16; i++) { for (int j = 0; j < 2; j++) { if (stepMap[i][j] >= 0 && get(queue[head][0], i) != get(queue[head][0], stepMap[i][j])) { //交换两个位置 uint_fast16_t flipped = flip(flip(queue[head][0], i), stepMap[i][j]); //如果没有重复的,加入队列尾部 if (!contains(queue, flipped, tail)) { queue[tail][0] = flipped; queue[tail][1] = queue[head][1] + 1; //如果到达结果,输出并停止程序 if (queue[tail][0] == goal) { printf("%"PRIuFAST16, queue[tail][1]); return 0; } tail++; } } } } //处理下一个 head++; } return 0; }
-
12019-02-12 10:23:36@
BFS+MAP判重
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<iostream> #include<vector> #include<queue> #include<map> using namespace std; const uint16_t factor[]={32768,16384,8192,4096,2048,1024,512,256,128,64,32,16,8,4,2,1}; int init[16],target[16]; uint16_t initc,targc; int d[2][4]={{0,0,-1,1}, //左,右,上,下 {-1,1,0,0}}; map<uint16_t,int> m; queue<uint16_t> q; uint16_t encode(int *a){ uint16_t code=0; for(int i=0;i<16;i++){ code *= 2; code += a[i]; } return code; } uint16_t exchange(uint16_t cur,int pos1,int pos2){ uint16_t next = cur^factor[pos1]^factor[pos2]; return next; } void bfs(){ uint16_t cur; while(!q.empty()){ cur = q.front(); for(int i=0;i<16;i++){ int curx=i/4, cury= i%4; for(int j=0;j<4;j++){ uint16_t next; int x = curx + d[0][j]; int y = cury + d[1][j]; if(x<0||x>3||y<0||y>3) continue; int pos1 =4*x+y, pos2 = 4*curx+cury; if(((cur&factor[pos1])>>(15-pos1)) == ((cur&factor[pos2])>>(15-pos2))) continue; else next = exchange(cur,pos1,pos2); if(!m.count(next)){ m[next]=m[cur]+1; q.push(next); if(next==targc){ cout<<m[next]; return; } } } } q.pop(); } } int main(){ int temp; for(int i=0;i<4;i++){ scanf("%d",&temp); for(int j=3;j>=0;j--){ init[4*i+j] = temp%10; temp /= 10; } } for(int i=0;i<4;i++){ scanf("%d",&temp); for(int j=3;j>=0;j--){ target[4*i+j] = temp%10; temp /= 10; } } initc = encode(init); targc = encode(target); m[initc] = 0; q.push(initc); if(initc==targc){ cout<<0; return 0; } bfs(); return 0; }
-
12018-10-27 20:27:09@
比较容易的一道广搜,由于状态比较少我们可以直接二进制压位来存储状态(险些用康拓展开的人)
主要是压缩和解压缩的过程#include<iostream> using namespace std; int minn[1<<16],dui[1<<16],map[4][4],xin[4][4]; int main() { char a; int i,j,chu=0,mo=0,head,tail,now,u,v,ha,lin,x,y,temp; for(i=0;i<4;i++) for(j=0;j<4;j++) { cin>>a; chu*=2; chu+=a-'0'; } for(i=0;i<4;i++) for(j=0;j<4;j++) { cin>>a; mo*=2; mo+=a-'0'; } //cout<<chu<<" "<<mo<<endl; head=1; tail=1; dui[1]=chu; minn[dui[1]]=1; while(tail<=head) { ha=dui[tail]; if(ha==mo) break; for(i=3;i>=0;i--) for(j=3;j>=0;j--) { map[i][j]=ha&1; ha/=2; } for(i=0;i<4;i++) for(j=0;j<4;j++) { if(j<3&&map[i][j]!=map[i][j+1]) { lin=0; temp=map[i][j]; map[i][j]=map[i][j+1]; map[i][j+1]=temp; for(u=0;u<4;u++) for(v=0;v<4;v++) { lin*=2; lin+=map[u][v]; } if(!minn[lin]) { head++; dui[head]=lin; minn[lin]=minn[dui[tail]]+1; } temp=map[i][j]; map[i][j]=map[i][j+1]; map[i][j+1]=temp; } if(i<3&&map[i][j]!=map[i+1][j]) { lin=0; temp=map[i][j]; map[i][j]=map[i+1][j]; map[i+1][j]=temp; for(u=0;u<4;u++) for(v=0;v<4;v++) { lin*=2; lin+=map[u][v]; } if(!minn[lin]) { head++; dui[head]=lin; minn[lin]=minn[dui[tail]]+1; } temp=map[i][j]; map[i][j]=map[i+1][j]; map[i+1][j]=temp; } } tail++; } cout<<minn[dui[tail]]-1; return 0; }
-
02019-01-18 20:46:04@
#include<stdio.h>
#include<stdlib.h>
using namespace std;const int nn=4;
//算法:从起点和终点同时开始宽搜,对着搜
//二叉查找树判重
struct node{
bool a[nn][nn];//一个状态
short step;//最小步数
node *next;
};
//用一个二进制数表示一个状态
int hash(node *p)
{
int i,j;
int n=0;
for(i=0;i<nn;i++)
for(j=0;j<nn;j++)
{
n=n<<1;
n=n|p->a[i][j];
}
return n;
}//二叉查找树的节点
struct node2{
int a;//节点的状态
short step;//到达节点的步数
node2 *left;
node2 *right;
};//判断能否做移动
//移动方向:0上,3下,1左,2右
//搜索中,每次只移动空白的格子
bool movable(node *p,int x,int y,int k)
{
//只移动空白格子
if(p->a[x][y]==1)
return 0;
//不能越界
if((x==nn-1)&&(k==3))
return 0;
if((x==0)&&(k==0))
return 0;
if((y==0)&&(k==1))
return 0;
if((y==nn-1)&&(k==2))
return 0;
//空白格子不和空白格子交换
if((k==3)&&(p->a[x+1][y]==0))
return 0;
if((k==0)&&(p->a[x-1][y]==0))
return 0;
if((k==1)&&(p->a[x][y-1]==0))
return 0;
if((k==2)&&(p->a[x][y+1]==0))
return 0;
return 1;
}
//拓展head节点,结果存在tail节点当中
void move(node *head,node *tail,int x,int y,int k)
{
int i,j;
for(i=0;i<nn;i++)
for(j=0;j<nn;j++)
tail->a[i][j]=head->a[i][j];
switch(k){
case 0:{
tail->a[x-1][y]=0;
break;
}
case 1:{
tail->a[x][y-1]=0;
break;
}
case 2:{
tail->a[x][y+1]=0;
break;
}
case 3:{
tail->a[x+1][y]=0;
break;
}
}
tail->a[x][y]=1;
tail->step=head->step+1;
tail->next=NULL;
}
//在二叉查找树中寻找一个元素。若是找到,则返回1;
//若是没有找到,则返回0,并插入该元素
bool search_insert(int l,short step,node2 *head)
{
node2 *p,*q;
p=head;
q=head;
while(q!=NULL)
{
p=q;
if(l<p->a)
q=p->left;
if(l>p->a)
q=p->right;
if(l==p->a) return 1;
}
if(q==NULL)
{
q=new node2;
if(l>p->a)
p->right=q;
if(l<p->a)
p->left=q;
q->left=NULL;
q->right=NULL;
q->a=l;
q->step=step;
return 0;
}
}
//在查找树中寻找元素,没找到返回0//
int search(int l,node2 *head)
{
node2 *p,*q;
p=head;
q=head;
while(q!=NULL)
{
p=q;
if(l==p->a) return (int) p->step;
if(l<p->a)
q=p->left;
if(l>p->a)
q=p->right;
}
if(q==NULL)
return 0;
}
//递归释放查找树
void release(node2 *head)
{
if(head->left!=NULL)
release(head->left);
if(head->right!=NULL)
release(head->right);
delete head;
}
int main()
{
int i,j,k;
node *head1,*tail1,*head2,*tail2,*p;//两条宽搜队列
node2 *hash1,*hash2; //两个查找树
int l,l0; //用于储存hash的结果,l0表示两条搜索树相遇的状态
char ch;//初始节点,队头
head1=new node;
for(i=0;i<nn;i++)
{
for(j=0;j<nn;j++)
{
scanf("%c",&ch);
head1->a[i][j]=(bool)(ch-'0');
}
scanf("%c",&ch);
}
scanf("%c",&ch);
head1->next=NULL;
head1->step=0;
tail1=head1;
//初始节点加入查找树
hash1=new node2;
hash1->a=hash(head1);
hash1->step=0;
hash1->left=NULL;
hash1->right=NULL;
//目标节点,队头
head2=new node;
for(i=0;i<nn;i++)
{
for(j=0;j<nn;j++)
{
scanf("%c",&ch);
head2->a[i][j]=(bool)(ch-'0');
}
scanf("%c",&ch);
}
head2->next=NULL;
head2->step=0;
tail2=head2;
//目标节点加入查找树
hash2=new node2;
hash2->a=hash(head2);
hash2->step=0;
hash2->left=NULL;
hash2->right=NULL;l0=-1;//标记两个搜索树未相遇。
if(hash(head2)==hash(head1))
l0=hash(head1);
while(l0==-1)
{
if(head1!=NULL)
{
//从初始状态开始搜索
for(i=0;(i<nn)&&(l0==-1);i++)
for(j=0;(j<nn)&&(l0==-1);j++)//i,j是16个节点位置
for(k=0;(k<4)&&(l0==-1);k++)//k是移动方向
if(movable(head1,i,j,k)==1)
{
p=new node;
move(head1,p,i,j,k);
//如果新的状态节点与已有的节点重复,则不加入搜索队列
l=hash(p);
if(search_insert(l,p->step,hash1)==1)
delete p;
else{
//加入搜索队列
tail1->next=p;
tail1=p;
}
//判断搜索树是否相遇
if(search(l,hash2)>0)
l0=l;
}
//释放已经被搜索过的队头
p=head1;
head1=head1->next;
delete p;if(l0>0)
break;
}
if(head2!=NULL)
{
//从目标状态开始搜索,基本过程和上文一致
for(i=0;(i<nn)&&(l0==-1);i++)
for(j=nn-1;(j>=0)&&(l0==-1);j--)
for(k=0;(k<4)&&(l0==-1);k++)
if(movable(head2,i,j,k)==1)
{
p=new node;
move(head2,p,i,j,k);
l=hash(p);
if(search_insert(l,p->step,hash2)==1)
delete p;
else{
tail2->next=p;
tail2=p;
}
//判断搜索树是否相遇
if(search(l,hash1)>0)
l0=l;
}
p=head2;
head2=head2->next;
delete p;
}
}
k=search(l0,hash1)+search(l0,hash2);
printf("%d\n",k);
//释放所有链表
release(hash1);
release(hash2);
while(head1!=NULL)
{
p=head1;
head1=head1->next;
delete p;
}
while(head2!=NULL)
{
p=head2;
head2=head2->next;
delete p;
}
} -
02018-08-13 11:21:32@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#define SIZE 17struct node {
char data[SIZE];
struct node *next;
};typedef struct queue{
struct node *first;
struct node *last;
int size;
}_queue;int visit[65536];
int pre[65536];
int xx[24] = {0,1,2,4,5,6,8,9,10,12,13,14,0,1,2,3,4,5,6,7,8,9,10,11};
int yy[24] = {1,2,3,5,6,7,9,10,11,13,14,15,4,5,6,7,8,9,10,11,12,13,14,15};bool qempty(_queue *q);
_queue *qnew();
void qpush(_queue *q, char str[]);
char *qpop(_queue *q);
int convert(char str[]);
void bfs(char start[], char end[]);
char *show(_queue *q);int main() {
char ch, start[SIZE], end[SIZE];
int i;
for (i = 0 ; i < SIZE -1; ) {
ch = getchar();
if (ch == '0' || ch == '1') {
start[i++] = ch;
}
}
start[i] = '\0';for (i = 0 ; i < SIZE -1; ) {
ch = getchar();
if (ch == '0' || ch == '1') {
end[i++] = ch;
}
}
end[i] = '\0';bfs(start, end);
return 0;
}void bfs(char start[], char end[]) {
_queue *q = qnew();
char str[17], tmp[17], ch;
int i;
if (strcmp(start, end) == 0) {
printf("0\n");
return;
}qpush(q, start);
visit[convert(start)] = 1;while (!qempty(q)) {
strcpy(str, qpop(q));
if (strcmp(str, end) == 0) {
break;
}// printf("%s\n", str);
for (i = 0 ; i < 24; i++) {
if (str[xx[i]] - '0' + str[yy[i]] - '0' == 1) {
strcpy(tmp,str);
ch = tmp[xx[i]];
tmp[xx[i]] = tmp[yy[i]];
tmp[yy[i]] = ch;
if (!visit[convert(tmp)]) {
visit[convert(tmp)] = 1;
qpush(q, tmp);
pre[convert(tmp)] = convert(str);
}
}
}
}int st, ed, step = 0;
st = convert(start);
ed = convert(end);
while (pre[ed] != st) {
ed = pre[ed];
step++;
}
printf("%d\n", step + 1);}
char *show(_queue *q) {
static char str[17];
strcpy(str, q->first->data);
return str;
}void qpush(_queue *q, char str[]) {
struct node *p = (struct node *) malloc(sizeof(struct node));
p->next = NULL;
strcpy(p->data, str);if (qempty(q)) {
q->size++;
q->first = q->last = p;
return;
}
q->size++;
q->last->next = p;
q->last = p;}
int convert(char str[]) {
int number = 0;
int i;
for (i = SIZE - 2 ; i >= 0; i--) {
if (str[i] == '1')
number = number + (1 << (15 - i));
}
return number;
}char *qpop(_queue *q) {
static char str[17];
strcpy(str, q->first->data);
struct node *p = q->first;
q->size--;
if (qempty(q)) {
q->last = q->first = q->first->next;
free(p);
return str;
}
q->first = q->first->next;
free(p);
return str;
}_queue *qnew() {
_queue *q = (_queue *) malloc (sizeof(_queue));
q->first = NULL;
q->last = q->first;
q->size = 0;
return q;
}bool qempty(_queue *q) {
return q->size == 0 ? true : false;
} -
02018-04-12 21:29:49@
思路简单,暴力BFS,
判重部分,因为16个格子均为0和1,所以可以把整个矩阵转换为一个二进制数
这个二进制数最大为十六位1(十进制65535),所以用一个bool形数组visited[65535]判重
读入时用一个string读入四个格子,再逐一转换成数字
上代码
```cpp
#include <iostream>
#include <queue>
#include <cmath>
using namespace std;struct matrix{
int a[4][4];
int step;
int decimal;
};struct pos{
int x,y;
};int start[4][4] , en[4][4];
bool visited[65536] = {false};
queue<matrix> q;
int mov[4][2] = {{1,0},{0,1},{0,-1},{-1,0}};int to_decimal(matrix m){
int result = 0;
int k = 15;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
result += (int)pow(2,k--) * m.a[i][j];
}
}
return result;
}bool is_visited(matrix m){
if(visited[m.decimal])
return true;
else{
visited[m.decimal] = true;
return false;
}
}bool check(matrix m){
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
if(m.a[i][j] != en[i][j])
return false;
}
}
return true;
}void move(matrix m){
int x,y,u,v,temp;
matrix t;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
for (int k = 0; k < 2; ++k) {
t = m;
u = i + mov[k][0];
v = j + mov[k][1];
if(u<0 || u >= 4 || v<0 || v>=4)
continue;
temp = t.a[u][v];
t.a[u][v] = t.a[i][j];
t.a[i][j] = temp;
t.step ++;
t.decimal = to_decimal(t);
if(!is_visited(t)){
q.push(t);
}
}
}
}
}int bfs(){
matrix m;
while(!q.empty()){
m = q.front();
q.pop();
if(check(m))
return m.step;
move(m);
}
}int main()
{
string s;
for (int i = 0; i < 4; ++i) {
cin >> s;
for (int j = 0; j < 4; ++j) {
start[i][j] = s[j] - '0';
}
}
for (int i = 0; i < 4; ++i) {
cin >> s;
for (int j = 0; j < 4; ++j) {
en[i][j] = s[j] - '0';
}
}matrix m;
m.step = 0;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
m.a[i][j] = start[i][j];
}
}
m.decimal = to_decimal(m);
visited[m.decimal] = true;
q.push(m);
cout << bfs() << endl;return 0;
}
``` -
02016-09-23 18:46:23@
找每两点的关系,转换成
8x8的数组,然后dfs即可#include<iostream> #include<cstdio> #include<cstring> #include<cmath> # include<algorithm> using namespace std; char a[5][5],b[5][5]; int c[9][3],d[9][3],e[9][9],v[9],w=99999; long long ans,q=0; void dfs(int t) { if(t==9) { if(ans<w)w=ans; } for(int i=1;i<=8;i++) { if(v[i]==0) { ans+=e[t][i]; v[i]=1; dfs(t+1); v[i]=0; ans-=e[t][i]; } } } int main() { for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { cin>>a[i][j]; if(a[i][j]=='1') { q++; d[q][1]=i; d[q][2]=j; } } q=0; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { cin>>b[i][j]; if(b[i][j]=='1'){q++;c[q][1]=i;c[q][2]=j; }} q=0; for(int j=1;j<=8;j++) for(int i=1;i<=8;i++) e[i][j]=abs(c[i][1]-d[j][1])+abs(c[i][2]-d[j][2]); dfs(1); cout<<w<<endl; //while(1); return 0; }
编译成功
测试数据 #0: Accepted, time = 0 ms, mem = 560 KiB, score = 10
测试数据 #1: Accepted, time = 15 ms, mem = 560 KiB, score = 10
测试数据 #2: Accepted, time = 0 ms, mem = 560 KiB, score = 10
测试数据 #3: Accepted, time = 15 ms, mem = 560 KiB, score = 10
测试数据 #4: Accepted, time = 0 ms, mem = 560 KiB, score = 10
测试数据 #5: Accepted, time = 0 ms, mem = 560 KiB, score = 10
测试数据 #6: Accepted, time = 15 ms, mem = 564 KiB, score = 10
测试数据 #7: Accepted, time = 0 ms, mem = 560 KiB, score = 10
测试数据 #8: Accepted, time = 0 ms, mem = 564 KiB, score = 10
测试数据 #9: Accepted, time = 0 ms, mem = 560 KiB, score = 10
Accepted, time = 45 ms, mem = 564 KiB, score = 100
-
02016-09-23 18:42:25@
八个循环的爆搜
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> # include<algorithm> using namespace std; char a[5][5],b[5][5]; int c[9][3]={0},d[9][3]={0},e[9][9],g[9],w=99999; long long ans[99999],q=0; int main() { for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { cin>>a[i][j];if(a[i][j]=='1'){q++;d[q][1]=i;d[q][2]=j;} } q=0; for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) { cin>>b[i][j]; if(b[i][j]=='1'){q++;c[q][1]=i;c[q][2]=j; }} q=0; for(int j=1;j<=8;j++) for(int i=1;i<=8;i++) e[i][j]=abs(c[i][1]-d[j][1])+abs(c[i][2]-d[j][2]); /* for(int j=1;j<=8;j++) { for(int i=1;i<=8;i++) cout<<e[i][j]<<" "; cout<<endl;} */ for(int i1=1;i1<=8;i1++) for(int i2=1;i2<=8;i2++) for(int i3=1;i3<=8;i3++) for(int i4=1;i4<=8;i4++) for(int i5=1;i5<=8;i5++) for(int i6=1;i6<=8;i6++) for(int i7=1;i7<=8;i7++) for(int i8=1;i8<=8;i8++) { if(i2!=i1&&i3!=i2&&i3!=i1&&i4!=i3&&i4!=i2&&i4!=i1&&i5!=i4&&i5!=i3&&i5!=i2&&i5!=i1&&i6!=i5&&i6!=i4&&i6!=i3&&i6!=i2&&i6!=i1&& i7!=i6&&i7!=i5&&i7!=i4&&i7!=i3&&i7!=i2&&i7!=i1&&i8!=i7&&i8!=i6&&i8!=i5&&i8!=i4&&i8!=i3&&i8!=i2&&i8!=i1) { q++; ans[q]=e[i1][1]+e[i2][2]+e[i3][3]+e[i4][4]+e[i5][5]+e[i6][6]+e[i7][7]+e[i8][8]; if(ans[q]<w)w=ans[q]; } } cout<<w; return 0; }
-
02016-09-21 14:18:05@
暴力BFS丝毫不虚
状态只有2^16,用hash判个重就丝毫不虚#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define maxn 1000010 using namespace std; typedef long long llg; int a[4][4],mu,b[4][4]; int d[maxn],l,r,de[maxn]; int zx[2]={1,0},zy[2]={0,1}; bool w[maxn]; char s[5]; int ya(){ int now=0; for(int i=0;i<4;i++) for(int j=0;j<4;j++) now<<=1,now+=a[i][j]; return now; } void jie(int x){ for(int i=3;i>=0;i--) for(int j=3;j>=0;j--) a[i][j]=x&1,x>>=1; } int main(){ File("a"); for(int i=0;i<4;i++){ scanf("%s",s); for(int j=0;j<4;j++) a[i][j]=s[j]-'0'; } d[r++]=ya(); w[d[0]]=1; for(int i=0;i<4;i++){ scanf("%s",s); for(int j=0;j<4;j++) a[i][j]=s[j]-'0'; } mu=ya(); if(mu==d[0]){printf("0");return 0;} while(l!=r){ int xx=de[l],u=d[l++],v; jie(u); for(int i=0;i<4;i++) for(int j=0;j<4;j++) for(int k=0;k<2;k++){ int x=i+zx[k],y=j+zy[k]; if(x>=0 && x<4 && y>=0 && y<4){ swap(a[i][j],a[x][y]); v=ya(); if(v==mu){printf("%d",xx+1);return 0;} if(!w[v]) w[v]=1,de[r]=xx+1,d[r++]=v; swap(a[i][j],a[x][y]); } } } }
-
02014-02-03 20:04:05@
我勒个去,编的麻烦死了。
其实就是读入两个方格+宽搜,只是判重注意一下。
我用数字判重,因为只有65536种情况嘛。
我和楼下的大神一起做,看我做的多慢。
哎,因为刚转C++,妈的,光是读入调试了一个小时。
C++不是段异常就是爆机。
BY JSB 绍兴一中万岁!
#include<stdio.h>
using namespace std;
long f[65537]={65537};
char x[65537][17]={},a[17]={},now[17]={};
long y[65537]={0};
long ok,h,t,start,end,check,i,j,p,k,go,ans;
char temp,oo;
int main()
{
for (i=1;i<=65536;i++) f[i]=65537;
for (i=1;i<=16;i++)
{
scanf("%c",&oo);
a[i]=oo;
if (i%4==0) scanf("%c",&oo);
y[1]=y[1]*2+a[i]-48;
}
scanf("%c",&oo);
ok=0;
for (p=1;p<=16;p++)
x[1][p]=a[p];
f[y[1]]=0;
for (i=1;i<=16;i++)
{
scanf("%c",&oo);
a[i]=oo;
if (i%4==0) scanf("%c",&oo);
ok=ok*2+a[i]-48;
}
h=0;t=1;ans=0;
while (h<t)
{
h++;
for (p=1;p<=16;p++) now[p]=x[h][p];
check=y[h];
for (i=1;i<=4;i++)
for (j=1;j<=3;j++)
{
start=(i-1)*4+j;end=start+1;
temp=now[start];now[start]=now[end];now[end]=temp;
go=0;
for (k=1;k<=16;k++) go=go*2+now[k]-48;
if (f[go]==65537)
{
t++;
for (p=1;p<=16;p++) x[t][p]=now[p];
y[t]=go;f[go]=f[check]+1;
if (ok==go) ans=f[go];
}
temp=now[start];now[start]=now[end];now[end]=temp;
}
for (i=1;i<=3;i++)
for (j=1;j<=4;j++)
{
start=(i-1)*4+j;end=start+4;
temp=now[start];now[start]=now[end];now[end]=temp;
go=0;
for (k=1;k<=16;k++) go=go*2+now[k]-48;
if (f[go]==65537)
{
t++;
for (p=1;p<=16;p++) x[t][p]=now[p];
y[t]=go;f[go]=f[check]+1;
if (ok==go) ans=f[go];
}
temp=now[start];now[start]=now[end];now[end]=temp;
}
if (ans>0) break;
}
printf("%ld",ans);
return 0;
} -
02014-02-03 18:55:12@
因为这题是固定的4*4方格,把黑色的视为1,把白色的视为0;状态总共是16^4=65536种,太方便了,判重连hash都不用了。直接可以用数组判重,然后宽搜直接秒杀
#include<stdio.h>
using namespace std;
struct o{
bool map[5][5];
//4*4的01矩阵
};bool gone[70000]={false}; //用来判重的。
o que[100000];long top=0,tail=0;long ans=0;o start,end;long s,e;bool isend=false;
long zm(o a) //01矩阵转数字
{
long ans=0;
for(int i=1;i<=4;i++)
{ ans*=16;
for(int j=1;j<=4;j++)if(a.map[i][j]==true)ans+=1<<(j-1);
}
return ans;
}
o nzj(long a) //数字转01矩阵
{ o k;for(int i=1;i<=4;i++)for(int j=1;j<=4;j++)k.map[i][j]=false;
for(int i=4;i>=1;i--)
{
long y=a%16;a/=16;
for(int j=1;j<=4;j++)if((1<<(j-1))&y>0)k.map[i][j]=true;
}
return k;
}
void kz(o s) 根据S这个01矩阵进行宽搜扩展。isend表示是否有答案。
{
for(int i=1;i<=4;i++)for(int j=1;j<=4;j++)
{
if(j+1<=4){bool temp=s.map[i][j];s.map[i][j]=s.map[i][j+1];s.map[i][j+1]=temp;long zb=zm(s);
if(zb==e){printf("%ld",ans);isend=true;return;}
if(gone[zb]==false){gone[zb]=true;tail++;que[tail]=s;}
temp=s.map[i][j];s.map[i][j]=s.map[i][j+1];s.map[i][j+1]=temp;}
if(i+1<=4){bool temp=s.map[i][j];s.map[i][j]=s.map[i+1][j];s.map[i+1][j]=temp;long zb=zm(s);
if(zb==e){printf("%ld",ans);isend=true;return;}
if(gone[zb]==false){gone[zb]=true;tail++;que[tail]=s;}
temp=s.map[i][j];s.map[i][j]=s.map[i+1][j];s.map[i+1][j]=temp;}
}
}
int main()
{
for(int i=1;i<=4;i++){for(int j=1;j<=4;j++){char u;scanf("%c",&u);start.map[i][j]=(u=='1');}char s1;scanf("%c",&s1);}
char s1;scanf("%c",&s1);//中间有一个换行符
for(int i=1;i<=4;i++){for(int j=1;j<=4;j++){char u;scanf("%c",&u);end.map[i][j]=(u=='1');}char s1;scanf("%c",&s1);}
//以上部分是读入,这里得用char读入,要注意换行符!
s=zm(start);e=zm(end);gone[s]=true;if(s==e){printf("0");return 0;}
tail++;que[tail]=start;top++;
while(true) //宽搜走起!
{ans++;long u=tail;
for(long i=top;i<=u;i++){kz(que[i]);if(isend)return 0;}
top=u;
}
return 0;
} -
02013-12-05 13:59:21@
bool doit(int sa, int sb, int sc, int sd)
{
int ha;
if (sc>0 && sc<5 && sd>0 && sd<5 && a[sa][sb]!=a[sc][sd])
{
swap(a[sa][sb],a[sc][sd]);
ha=hash(a);
if (!v[ha]) list[tail]=ha, ans[tail]=ans[head]+1, tail++;
v[ha]=true;
swap(a[sa][sb],a[sc][sd]);
}
if (ha==js) return true;
return false;
}int bfs()
{
memset(v, 0, sizeof(v));
ans[1]=0; list[1]=cs;
while (head<tail)
{
int k=list[head];
if (k==js) return ans[head];
for (int i=4; i>=1; i--)
for (int j=4; j>=1; j--)
{
a[i][j]=k%2;
k/=2;
}
for (int i=1; i<=4; i++)
{
for (int j=1; j<=4; j++)
{
if (doit(i,j,i,j-1)) return ans[tail-1];
if (doit(i,j,i,j+1)) return ans[tail-1];
if (doit(i,j,i-1,j)) return ans[tail-1];
if (doit(i,j,i+1,j)) return ans[tail-1];
}
}
head++;
}
}//部分代码
-
02012-11-18 17:37:01@
追奇葩的hash
├ 测试数据 01:答案正确... (0ms, 20304KB)
├ 测试数据 02:答案正确... (0ms, 20304KB)
├ 测试数据 03:答案正确... (15ms, 20304KB)
├ 测试数据 04:答案正确... (14ms, 20304KB)
├ 测试数据 05:答案正确... (31ms, 20304KB)
├ 测试数据 06:答案正确... (15ms, 20304KB)
├ 测试数据 07:答案正确... (46ms, 20304KB)
├ 测试数据 08:答案正确... (31ms, 20304KB)
├ 测试数据 09:答案正确... (31ms, 20304KB)
├ 测试数据 10:答案正确... (31ms, 20304KB)type arr=array[1..16] of 0..1;
rec=record
l:longint;
s:arr;
end;
var a,b:arr;
i:integer;
q:array[1..1000000] of rec;
f,r:longint;
c:char;
h:array[0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1,0..1] of boolean;procedure add(x:arr);
begin
h[x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15],x[16]]:=true;
end;function have(x:arr):boolean;
begin
have:=h[x[1],x[2],x[3],x[4],x[5],x[6],x[7],x[8],x[9],x[10],x[11],x[12],x[13],x[14],x[15],x[16]];
end;procedure bfs;
function can(x,y:longint):boolean;
begin
if not((x+y=17)) then begin
if q[f].s[x]=q[f].s[x+y] then exit(false);
case x of
1:exit((y=4)or(y=1));
2,3:exit(y-4);
4:exit((y=-1)or(y=4));
5,9:exit(y-1);
6,7,10,11:exit(true);
8,12:exit(y1);
13:exit((y=1)or(y=-4));
14,15:exit(y4);
16:exit((y=-1)or(y=-4));
end;
end else can:=false;
end;
const c:array[1..4] of longint=(1,-1,4,-4);
var i,j:longint;
s:arr;
function deng:boolean;
var i:integer;
begin
for i:=1 to 16 do
if s[i]b[i] then exit(false);
exit(true);
end;
begin
s:=a;
if deng then begin writeln(0); halt; end;
f:=1; r:=1;
q[1].s:=a;
add(a);
repeat
for j:=1 to 16 do
for i:=1 to 4 do
if can(j,c[i]) then begin
s:=q[f].s;
s[j]:=1-s[j];
s[j+c[i]]:=1-s[j+c[i]];
if not have(s) then begin
inc(r);
q[r].l:=q[f].l+1;
q[r].s:=s;
add(s);
if deng then begin writeln(q[r].l); halt; end;
end;
end;
inc(f);
until f>r;
end;begin
for i:=1 to 16 do begin
read(c);
if i mod 4=0 then readln;
a[i]:=ord(c)-48;
end;
readln;
for i:=1 to 16 do begin
read(c);
if i mod 4=0 then readln;
b[i]:=ord(c)-48;
end;
readln;
bfs;
end. -
02012-08-27 23:54:43@
费用流。。少打了个+16居然有90分害我查了好久
-
02009-10-30 17:20:42@
不用位运算,可以直接dfs..
先处理出起始状态和结束状态的差别,然后dfs枚举这些差别的组合即可.. -
02009-10-27 20:42:56@
神奇的位运算!
ORZ! -
02009-10-25 10:38:11@
#include
int main()
{
int i, j, mb=0, v[0x10000]={}, p[0x10000]={}, q[0x10000]={}, t=0, h=1, x,
e[]={0xc000,0x6000,0x3000,0xc00,0x600,0x300,0xc0,0x60,0x30,0xc,0x6,0x3,
0x8800,0x4400,0x2200,0x1100,0x880,0x440,0x220,0x110,0x88,0x44,0x22,0x11};
for (i=0; i -
02009-10-07 17:18:21@
var hash:array[0..70000] of longint;
c:array[1..2,1..24] of integer=(...);
f:array[0..70000] of longint;
now,pre,aim,i,j,k,p,sum:longint;
s:string;procedure ready;
begin
sum:=0;
for i:=1 to 4 do
begin
readln(s);
for j:=1 to 4 do sum:=sum+(ord(s[j])-ord('0'))*trunc(exp(((i-1)*4+j-1)*ln(2)));
end;
pre:=sum;
readln(s);
sum:=0;
for i:=1 to 4 do
begin
readln(s);
for j:=1 to 4 do sum:=sum+(ord(s[j])-ord('0'))*trunc(exp(((i-1)*4+j-1)*ln(2)));
end;
aim:=sum;
end;begin
ready;
if pre=aim then begin writeln('0');halt;end;
f[1]:=pre;
k:=1;p:=1;
while f[k]>0 do
begin
for i:=1 to 24 do
if ((f[k] and (1 shl (c[1,i]-1))>0) and (f[k] and (1 shl (c[2,i]-1))=0)) or ((f[k] and (1 shl (c[1,i]-1))=0) and (f[k] and (1 shl (c[2,i]-1))>0))
then
beginnow:=f[k] xor (1 shl (c[1,i]-1));
now:=now xor (1 shl (c[2,i]-1));if now=aim then
begin
writeln(hash[f[k]]+1);
halt;
end;if hash[now]=0 then
begin
hash[now]:=hash[f[k]]+1;
inc(p);
f[p]:=now;
end;end;
inc(k);
end;
end.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
就50多行额。
bfs+位运算。 -
02009-10-07 11:14:48@
编译通过...
├ 测试数据 01:答案正确... 0ms
├ 测试数据 02:答案正确... 0ms
├ 测试数据 03:答案正确... 0ms
├ 测试数据 04:答案正确... 0ms
├ 测试数据 05:答案正确... 0ms
├ 测试数据 06:答案正确... 0ms
├ 测试数据 07:答案正确... 0ms
├ 测试数据 08:答案正确... 0ms
├ 测试数据 09:答案正确... 0ms
├ 测试数据 10:答案正确... 0ms
---|---|---|---|---|---|---|---|-
Accepted 有效得分:100 有效耗时:0mstype
atp = record
data,time : longint;
end;
var
hash : array [0..70000] of boolean;
q : array [1..1000000*3] of atp;
st,ans : longint;procedure init;
var i , j : longint; str : string;
begin
ans := 0; st := 0;
for i := 1 to 4 do
begin
readln(str);
for j := 1 to 4 do st := st*2 + ord(str[j]) - 48;
end;
readln;
for i := 1 to 4 do
begin
readln(str);
for j := 1 to 4 do ans := ans*2 + ord(str[j]) - 48;
end;
end;function hashit(x : longint) : boolean;
begin if hash[x] then exit(false); hash[x] := true; exit(true); end;function swap(x,i,j : longint) : longint;
var k : longint;
begin exit(x - 1 shl (i-1) + 1 shl (j-1)); end;procedure main;
var i , j , x , l , r , k : longint; d,t : atp;
begin
q[1].time := 0; q[1].data := st; l := 1; r := 1; fillchar(hash,sizeof(hash),0);
hashit(st);
while l