枚举
画家问题
注意无解的情况的判断
http://poj.org/problem?id=1681
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#define N 20
using namespace std;
int puzzle[N][N],press[N][N];
int n;
bool success;
bool guess()
{
int r,c;
for(r=1;r<n;r++)
{
for(c=1;c<=n;c++)
{
press[r+1][c]=(puzzle[r][c]+press[r][c]+press[r-1][c]+press[r][c-1]+press[r][c+1])%2;
}
}
//看最后一行是否全被染为黄色
for(c=1;c<=n;c++)
{
if( (press[n][c-1]+press[n][c+1]+press[n-1][c]+press[n][c])%2!=puzzle[n][c] )
return false;
}
return true;
}
void enumate()
{//只需一次枚举第一行的状态
int c;
for(c=1;c<=n;c++)
press[1][c]=0;
while(guess()==false)
{
press[1][1]++;
c=1;
while(press[1][c]>1)
{
press[1][c]=0;
c++;
press[1][c]++;
}
//注意这里的处理
if(press[1][n+1]==1)
{//说明枚举了所有状态都没有成功
success=false;
break;
}
}
return;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
success=true;
memset(press,0,sizeof(press));
memset(puzzle,0,sizeof(puzzle));
scanf("%d",&n);
getchar();
char buf[N];
for(int i=1;i<=n;i++)
{
gets(buf+1);
for(int j=1;j<=n;j++)
{
if(buf[j]=='w')
puzzle[i][j]=1;//1表示白色
else
puzzle[i][j]=0;
}
}
enumate();
if(success)
{
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(press[i][j]==1)
cnt++;
printf("%d\n",cnt);
}
else
printf("inf\n");
}
return 0;
}
拨钟问题:
依次枚举每种操作
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
using namespace std;
/*
每个移动可以操作次数为3次,就可以出现4种状态
因为时钟的状态为4个
和熄灯问题类似,熄灯共两种状态,所以操作总共就1次
*/
int M[9][9]={
1,1,0,1,1,0,0,0,0,
1,1,1,0,0,0,0,0,0,
0,1,1,0,1,1,0,0,0,
1,0,0,1,0,0,1,0,0,
0,1,0,1,1,1,0,1,0,
0,0,1,0,0,1,0,0,1,
0,0,0,1,1,0,1,1,0,
0,0,0,0,0,0,1,1,1,
0,0,0,0,1,1,0,1,1
};
int buf[9];
int ans[9];
int main()
{
for(int i=0;i<9;i++)
{
scanf("%d",&buf[i]);
}
int m1,m2,m3,m4,m5,m6,m7,m8,m9;//代表题目给的9种操作 ,0代表不操作,1,2,3代表操作1,2,3次
int i,cnt;
int mins=50;
for(m1=0;m1<=3;m1++)
{
for(m2=0;m2<=3;m2++)
{
for(m3=0;m3<=3;m3++)
{
for(m4=0;m4<=3;m4++)
{
for(m5=0;m5<=3;m5++)
{
for(m6=0;m6<=3;m6++)
{
for(m7=0;m7<=3;m7++)
{
for(m8=0;m8<=3;m8++)
{
for(m9=0;m9<=3;m9++)
{
bool flag=true;
for(i=0;i<9;i++)
{//代表ABCDEFGHI 9个时钟 0,1,2,3共4种状态
if((buf[i]+m1*M[0][i]+m2*M[1][i]+m3*M[2][i]+m4*M[3][i]+m5*M[4][i]+m6*M[5][i]+m7*M[6][i]+m8*M[7][i]+m9*M[8][i])%4!=0)
{
flag=false;
break;
}
}
if(flag)
{
cnt=m1+m2+m3+m4+m5+m6+m7+m8+m9;
if(cnt<mins)
{
mins=cnt;
ans[0]=m1;
ans[1]=m2;
ans[2]=m3;
ans[3]=m4;
ans[4]=m5;
ans[5]=m6;
ans[6]=m7;
ans[7]=m8;
ans[8]=m9;
}
}
}
}
}
}
}
}
}
}
}
bool mark=false;
for(int j=0;j<9;j++)
{
while(ans[j]--)
{
if(!mark)
printf("%d",j+1);
else
printf(" %d",j+1);
mark=true;
}
}
printf("\n");
return 0;
}
恼人的青蛙
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<algorithm>
#define N 5005
using namespace std;
struct PLANT{
int x,y;
}plant[N];
int r,c,n,dx,dy,px,py,steps,maxs=2;
int myCompare(const void* ele1,const void* ele2)
{
PLANT *p1,*p2;
p1=(PLANT*)ele1;
p2=(PLANT*)ele2;
if((p1->x) == (p2->x))
return (p1->y-p2->y);//从小到大排序
else
return (p1->x-p2->x);
}
int searchPath(PLANT p,int dx,int dy)
{
PLANT tmp;
int step;
tmp.x=p.x+dx;
tmp.y=p.y+dy;
step=2;
while(tmp.x<=r && tmp.x>=1 && tmp.y<=c && tmp.y>=1)
{//下一步在稻田内,但是又没被踩,说明该路径不是被踩路径
//否则,继续下一步
if(!bsearch(&tmp,plant,n,sizeof(PLANT),myCompare))
{
step=0;
break;
}
tmp.x+=dx;
tmp.y+=dy;
step++;
}
return step;
}
int main()
{
bool flag=false;
scanf("%d%d",&r,&c);
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d%d",&plant[i].x,&plant[i].y);
}
qsort(plant,n,sizeof(PLANT),myCompare);//按行坐标从小到大排序
//依次枚举前两步,注意剪枝
for(int i=0;i<n-2;i++)
{
for(int j=i+1;j<n-1;j++)
{
dx=plant[j].x-plant[i].x;//dx一定 >=0
dy=plant[j].y-plant[i].y;//dy不一定
px=plant[i].x-dx;
py=plant[i].y-dy;//点必须在稻田外才符合
if(px>=1 && px<=r && py>=1 && py<=c)
continue;
if(plant[i].x+maxs*dx>r)
break;//如果第三个点在稻田外,那么不用往下列举了,接下来的dx肯定会越来越大
py=plant[i].y+maxs*dy;
if(py>c|| py<1)
{//如果y方向上只能满足第三个点在稻田外,那么必须依次列举,因为接下来的点有可能dy会更小
continue;
}
steps=searchPath(plant[j],dx,dy);
if(steps>=maxs)
{
maxs=steps;
flag=true;
}
}
}
//
if(flag)
printf("%d\n",maxs);
else
printf("0\n");
return 0;
}