luogu2761(状态压缩+bfs)

怎么看都像是状压bfs,因为时间复杂度已经快爆了所以感觉应该会有什么更快的方法。。毕竟是放在网络流24题嘛。。

结果真的是状压bfs= =!(心中踏过无数只草泥马)

状压bfs好像大学还没写过。。还是留个念。。。

直接位运算压缩状态。。然后对于那写包不包含的啦,去bug加bug啦,要分开来压缩,就是分成包含的,不包含的,加bug的,去bug的,独立开来处理。。。

时间复杂度大概是O(m*2^n)这样吧。。大概都1e8了。。然而跑起来才4ms这真的。。。

反正就是道烂题。。。



/**
 *        ┏┓    ┏┓
 *        ┏┛┗━━━━━━━┛┗━━━┓
 *        ┃       ┃  
 *        ┃   ━    ┃
 *        ┃ >   < ┃
 *        ┃       ┃
 *        ┃... ⌒ ...  ┃
 *        ┃       ┃
 *        ┗━┓   ┏━┛
 *          ┃   ┃ Code is far away from bug with the animal protecting          
 *          ┃   ┃   神兽保佑,代码无bug
 *          ┃   ┃           
 *          ┃   ┃        
 *          ┃   ┃
 *          ┃   ┃           
 *          ┃   ┗━━━┓
 *          ┃       ┣┓
 *          ┃       ┏┛
 *          ┗┓┓┏━┳┓┏┛
 *           ┃┫┫ ┃┫┫
 *           ┗┻┛ ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-12
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 2000005
#define nm 205
#define pi 3.1415926535897931
using namespace std;
const int inf=1000000005;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}



queue<int>q;
int d[NM],n,b1[nm],b2[nm],f1[nm],f2[nm],a[nm],tot,m;
bool v[NM];
char _s[nm];

void spfa(){
	inc(i,0,tot)d[i]=inf;
	d[tot]=0;v[tot]++;q.push(tot);
	while(!q.empty()){
		int t=q.front();q.pop();v[t]=false;
		inc(i,1,m){
			int _t=(t&f1[i])|f2[i];
			if((t&b1[i])==b1[i]&&(t&b2[i])==0&&d[_t]>d[t]+a[i]){
				d[_t]=d[t]+a[i];
				if(!v[_t])v[_t]++,q.push(_t);
			}
		}
	}
}


int main(){
	n=read();m=read();tot=succ(n)-1;
	inc(i,1,m){
		a[i]=read();
		scanf("%s",_s+1);
		inc(j,1,n){
			b1[i]<<=1;b2[i]<<=1;
			if(_s[j]=='+')b1[i]++;
			if(_s[j]=='-')b2[i]++;
		}
		scanf("%s",_s+1);
		inc(j,1,n){
			f1[i]<<=1;f2[i]<<=1;
			if(_s[j]=='+')f2[i]++;
			if(_s[j]=='-')f1[i]++;
		}
		f1[i]^=tot;
		//printf("%d %d %d %d\n",b1[i],b2[i],f1[i],f2[i]);
	}
	spfa();
	//inc(i,0,tot)printf("%d:%d\n",i,d[i]);
	if(d[0]<inf)printf("%d\n",d[0]);else printf("0\n");
	return 0;
}



P2761 软件补丁问题


题目背景

none!

题目描述

T 公司发现其研制的一个软件中有 n 个错误,随即为该软件发放了一批共 m 个补丁程序。每一个补丁程序都有其特定的适用环境,某个补丁只有在软件中包含某些错误而同时又不包含另一些错误时才可以使用。一个补丁在排除某些错误的同时,往往会加入另一些错误。

换句话说,对于每一个补丁 i,都有 2 个与之相应的错误集合 B1[i]和 B2[i],使得仅当软件包含 B1[i]中的所有错误,而不包含 B2[i]中的任何错误时,才可以使用补丁 i。补丁 i 将修复软件中的某些错误 F1[i],而同时加入另一些错误 F2[i]。另外,每个补丁都耗费一定的时间。

试设计一个算法,利用 T 公司提供的 m 个补丁程序将原软件修复成一个没有错误的软件,并使修复后的软件耗时最少。对于给定的 n 个错误和 m 个补丁程序,找到总耗时最少的软件修复方案。

输入输出格式

输入格式:

第 1 行有 2 个正整数 n 和 m,n 表示错误总数,m表示补丁总数,1<=n<=20, 1<=m<=100。

接下来 m 行给出了 m 个补丁的信息。每行包括一个正整数,表示运行补丁程序 i 所需时间,以及 2 个长度为 n 的字符串,中间用一个空格符隔开。

第 1 个字符串中,如果第 k 个字符 bk 为“+”,则表示第 k 个错误属于 B1[i],若为“-”,则表示第 k 个错误属于 B21[i],若为“0”,则第 k 个错误既不属于 B1[i]也不属于 B2[i],即软件中是否包含第 k 个错误并不影响补丁 i 的可用性。

第 2 个字符串中,如果第 k 个字符 bk为“-”,则表示第 k 个错误属于 F1[i],若为“+”,则表示第 k 个错误属于 F2[i],若为“0”,则第 k 个错误既不属于 F1[i]也不属于 F2[i],即软件中是否包含第 k 个错误不会因使用补丁i 而改变。

输出格式:

程序运行结束时,将总耗时数输出。如果问题无解,则输出 0。

输入输出样例

输入样例#1: 复制
3 3
1 000 00-
1 00- 0-+
2 0-- -++
输出样例#1: 复制
8

说明

none!


猜你喜欢

转载自blog.csdn.net/qkoqhh/article/details/80204592