POJ2908 Quantum 光搜+优先队列好题目

这是一道好题目啊,放假回头准备练练手的,发现是我弱爆了。。。首先一开始就大致确定好了思路,画了一会,发现优先队列直接贪心就可以的,接下来就敲了,一开始都用了字符串导致一直WA,做了一个下午把,后来发现了错的地方,然后接着TLE,然后看网上说是不要用STL的优先队列,自己写一个小顶堆,然后套了个模板,结果还是TLE,认为自己的模板错了,可是发现跟别人的一致,又弄到了现在,实在找不出哪里有问题,然后看题解了,发现了一篇转化着做的,把字符串转化成二进制的十进制数,这样就直接利用位运算来做,总算是A掉了,去尝试了记忆化搜索,因为转化后有状态标记的,试了几次,发现不行,就放弃了,一天就做了这一道题目。。。


参考了:戳这里

做法还是比较清晰的,画一画再大胆猜测一下,留个纪念,毕竟做了一天,题意说不清楚引用别人的:题目给出nop个操作,由N(什么都不做),S(置1),C(置0),F(反转)等基本操作组成,每一种操作会产生不同的热量。又给出nw组初始字符串和目标字符串,要求出将初始字符串转化成目标字符串至少需要产生的热量;有可能没有解,此时输出“NP”


直接bfs,类似于dfs的暴力枚举一样,队列循环,每一次都去扫一遍nop的所有操作,然后花费小的优先,暴力寻找,找到跳出,找不到就是没有答案的,同时还要标记此状态是否已经出现过了,每一个求答案都得要把状态标记数组清空,前几天因为用了memset总是TLE,坑了许久,这题目还是有点虚的,还好没有被坑


以后做题要提醒自己发现思路了,要先好好想想怎么样做最方便,不然也把自己绕醉了~


typedef struct Node {
	int val;
	int ss;
	friend bool operator<(Node x,Node y) {
		return x.val > y.val;
	}
};

int n,nop,nw;

int make_true[30 + 5],make_false[30 + 5],xo[30 + 5],w[30 + 5];

bool vis[1<<22];

priority_queue<Node > q;

void init() {
	memset(make_true,0,sizeof(make_true));
	memset(make_false,0,sizeof(make_false));
	memset(xo,0,sizeof(xo));
	memset(w,0,sizeof(w));
}

bool input() {
	while(cin>>n>>nop>>nw) {
		for(int i=0;i<nop;i++) {
			char s[20 + 5];
			scanf("%s %d",&s,&w[i]);
			for(int j=0;j<n;j++) {
				make_true[i] <<= 1;
				make_false[i] <<= 1;
				xo[i] <<= 1;
				make_false[i]++;
				if(s[j] == 'S')make_true[i]++;
				else if(s[j] == 'F')xo[i]++;
				else if(s[j] == 'C')make_false[i]--;
			}
		}
		return false;
	}
	return true;
}

int slove(char *s) {
	int len = strlen(s);
	int ret = 0;
	for(int i=0;i<len;i++) {
		ret <<= 1;
		if(s[i] == '1')ret++;
	}
	return ret;
}

int bfs(int start,int end) {
	memset(vis,false,sizeof(vis));
	while(!q.empty()) q.pop();
	Node s,e;
	s.val = 0;
	s.ss = start;
	q.push(s);
	while(!q.empty()) {
		s = q.top();
		q.pop();
		int pos = s.ss;
		if(vis[pos])continue;
		if(pos == end)return s.val;
		vis[pos] = true;
		for(int i=0;i<nop;i++) {
			int tmp = ((pos&make_false[i])|make_true[i])^xo[i];
			if(!vis[tmp]) {
				e.ss = tmp;
				e.val = s.val + w[i];
				q.push(e);
			}
		}
	}
	return -1;
}

void cal() {
	int q = nw;
	bool flag = false;

	while(q--) {
		char start[20 + 5],end[20 + 5];
		scanf("%s %s",start,end);
		if(flag)putchar(' ');
		else flag = true;
		int s = slove(start);
		int e = slove(end);
		int ans = bfs(s,e);
		if(ans < 0)printf("NP");
		else printf("%d",ans);
		//cout<<"-->";
	}
	puts("");
}

void output() {

}

int main() {
	int t;
	cin>>t;
	while(t--) {
		init();
		if(input())return 0;
		cal();
		output();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值