非hash/位运算搜法

利用题目的隐含条件,倒着往前搜:现在能治好的病,在过去才可以得,现在治不好,过去就不能得= =……
这样可以减少许多状态!
好吧看代码吧,有注释,很好理解~
循环队列开小了……之前只开了200所以WA90 QAQ

//Vijos 1026
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define r(i,j,n) for(int i=j;i<=n;++i)
#define pb push_back
using namespace std;
const int N=101;
//倒着搜:因为现在治不好的以后不知道什么时候可能能治好,而倒着搜的话,只有现在能治好的病,过去才可以得
int n,m,a[N][11],b[2200][11],Q[2200],num[2200];

void out(int x)
{
printf("this is %d\n",x);
r(i,1,n)
printf("%d ",b[x][i]);
cout <<endl;
}//debug

int main()
{
freopen("file.in","r",stdin);
// freopen("file.out","w",stdout);
scanf("%d%d",&n,&m);
int l=0,r=0;
r(i,1,m){
int sign=1;
r(j,1,n){
scanf("%d",&a[i][j]);
if (a[i][j]==-1) sign=0;
}
if (sign) { Q[r++]=i; num[r-1]=1; r(k,1,n) b[r-1][k]=a[i][k]; }
}

if (!r) {printf("The patient will be dead.\n"); return 0;}

while(l!=r){
bool check=1;
r(k,1,n) if (b[l][k]!=1){check=0;break;}
if (check) {printf("%d\n",num[l]);}
r(j,1,m){
if (j==Q[l]) continue;//刚刚吃过的药再吃没意义……
// out(l);
bool sign1=1,sign2=0;
r(k,1,n)
if (a[j][k]==-1 && b[l][k]!=1) {sign1=0;break;}//如果过去要得的病现在治不了,则不扩展
r(k,1,n)
if (a[j][k]==1 && b[l][k]==0) {sign2=1;break;}//如果对当前状态无增益(不能多治任何一种病)则不扩展
// cout <<sign1<<" "<<sign2<<endl;
if (sign1 && sign2) {
Q[r]=j;
num[r]=num[l]+1;//用的药的数量加一
r(k,1,n)
if(a[j][k]==1) b[r][k]=1;
else b[r][k]=b[l][k];//更新状态
r=(r+1)%2000;//循环队列,队尾指针加一
// out(r-1);
bool check=1;
r(k,1,n) if (b[r-1][k]!=1){check=0;break;}
if (check) {printf("%d\n",num[r-1]); return 0;}//判断当前是否能治愈
}
}
l=(l+1)%2000;//队首指针+1(循环队列)
}
printf("The patient will be dead.\n");
return 0;
}
//90

0 条评论

目前还没有评论...

信息

ID
1026
难度
6
分类
搜索 | 搜索与剪枝 点击显示
标签
(无)
递交数
3640
已通过
1102
通过率
30%
被复制
19
上传者