书山有径勤为路>>>>>>>>

<<<<<<<<学海无涯苦作舟!

DFS解决任意组合问题

描述

在IOI98的节日宴会上,我们有N(10<=N<=100)盏彩色灯,他们分别从1到N被标上号码。 这些灯都连接到四个按钮:

按钮1:当按下此按钮,将改变所有的灯:本来亮着的灯就熄灭,本来是关着的灯被点亮。 
按钮2:当按下此按钮,将改变所有奇数号的灯。
按钮3:当按下此按钮,将改变所有偶数号的灯。
按钮4:当按下此按钮,将改变所有序号是3*K+1(K>=0)的灯。例如:1,4,7...

一个计数器C记录按钮被按下的次数。当宴会开始,所有的灯都亮着,此时计数器C为0。

你将得到计数器C(0<=C<=10000)上的数值和经过若干操作后某些灯的状态。写一个程序去找出所有灯最后可能的与所给出信息相符的状态,并且没有重复。

格式

PROGRAM NAME: lamps

INPUT FORMAT:

(file lamps.in)

不会有灯会在输入中出现两次。

第一行: N。

第二行: C最后显示的数值。

第三行: 最后亮着的灯,用一个空格分开,以-1为结束。

第四行: 最后关着的灯,用一个空格分开,以-1为结束。

OUTPUT FORMAT:

(file lamps.out)

每一行是所有灯可能的最后状态(没有重复)。每一行有N个字符,第1个字符表示1号灯,最后一个字符表示N号灯。0表示关闭,1表示亮着。这些行必须从小到大排列(看作是二进制数)。

如果没有可能的状态,则输出一行'IMPOSSIBLE'。

SAMPLE INPUT

10 //一共有10盏灯
1  //按钮的操作次数
-1 //on,以-1结束
7 -1 //off,以-1结束

在这个样例中,有10盏灯,只有1个按钮被按下。最后7号灯是关着的。

SAMPLE OUTPUT

0000000000
0101010101
0110110110

在这个样例中,有三种可能的状态:

所有灯都关着

1,4,7,10号灯关着,2,3,5,6,8,9亮着。

1,3,5,7,9号灯关着,2, 4, 6, 8, 10亮着。

 

注意:这里一共有4种操作,那这里所说的任意组合就是这四种操作之间的任意组合。要搞清楚。

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<string.h>
#include<algorithm>
using namespace std;
string s[102];
bool off[102],on[102],ans[102],v[5];
int n,c,sum;
bool cmp(string x,string y)
{
  return x<y;
}
char find(bool f)
{
  if (f) return '1';
  return '0';
}
void check()
{
  int k=0;
  for (int i=1; i<=n; ++i)
  {
    if (on[i]&&!ans[i]) return; //标准为开,而ans为!开,不行
    if (off[i]&&ans[i]) return; //标准为关,而ans为关,不行
  }
  for (int i=1; i<=4; ++i)
  if (v[i]) k++; //v[i]可行,k记录四种开关的操作次数,不能大于C
  if (k>c) return;
  if ((c-k)%2!=0) return;

  //查找成功,统计结果
  for (int i=1; i<=n; ++i)
  s[sum]=s[sum]+find(ans[i]);
  sum++;
}
void dfs(int x)
{
  if (x>4)
  {
    check();
    return;
  }
  dfs(x+1); //如果搜索了。

  v[x]=true;
  if (x==1) //开关1的操作
    for (int i=1; i<=n; i+=1)
      ans[i]=!ans[i];
  if (x==2) //开关2的操作
    for (int i=1; i<=n; i+=2)
      ans[i]=!ans[i];
  if (x==3) //开关3的操作
    for (int i=0; i<=n; i+=2)
      ans[i]=!ans[i];
  if (x==4) //开关4的操作
    for (int i=0; i<=n/3; i++)
      ans[i*3+1]=!ans[i*3+1];
  dfs(x+1); //还原刚才搜索的东西,为了下次的搜索
  v[x]=false;
  if (x==1) //开关1的操作
    for (int i=1; i<=n; i+=1)
      ans[i]=!ans[i];
  if (x==2) //开关2的操作
    for (int i=1; i<=n; i+=2)
      ans[i]=!ans[i];
  if (x==3) //开关3的操作
    for (int i=0; i<=n; i+=2)
      ans[i]=!ans[i];
  if (x==4) //开关4的操作
    for (int i=0; i<=n/3; i++)
      ans[i*3+1]=!ans[i*3+1];
}
int main()
{
  cin>>n>>c;
  int k;
  sum=0;
  memset(v,0,sizeof(v));
  memset(on,0,sizeof(on));
  memset(ans,1,sizeof(ans));
  memset(off,0,sizeof(off));
  while(cin>>k && k!=-1) on[k]=true;
  while(cin>>k && k!=-1) off[k]=true;
  dfs(1);
  sort(s,s+sum,cmp);
  for (int i=0; i<sum; ++i) cout<<s[i]<<endl;
  if (sum==0) cout<<"IMPOSSIBLE"<<endl;
  return 0;
}

 

posted on 2011-10-24 23:02  More study needed.  阅读(387)  评论(0编辑  收藏  举报

导航

书山有径勤为路>>>>>>>>

<<<<<<<<学海无涯苦作舟!