枚举问题总结

枚举

画家问题

注意无解的情况的判断

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值