LUOGU 2761 软件补丁问题 网络流24题

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/90748420

title

LUOGU 2761
题目背景

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!

analysis

正解是状压 D P DP s p f a spfa 转移。

因为最多只有 20 20 个补丁,所以我们可以开一个 1 &lt; &lt; 20 1&lt;&lt;20 的数组来记录每个病毒的状态。
一开始有 n n 个病毒,也就是起始点是 ( 1 &lt; &lt; n ) 1 (1&lt;&lt;n)-1 ,目标点就是 0 0 ,也就是一个病毒都没有。
我们记录每个补丁的 b 1 b 2 f 1 f 2 b_1,b_2,f_1,f_2,
如果这个补丁可以修复,那就 b 1 [ i ] b_1[i] 和当前状态每一位 1 |1 之后还是 n n ,和 b 2 [ i ] &amp; b_2[i] \&amp; 之后 = = 0 ==0
然后产生的影响就是 f 1 [ i ] f_1[i] 中的位 = 0 =0 f 2 [ i ] f_2[i] 中的位 = 1 =1

修复和添加错误的时候不能用减法。。
因为修复的错误可能当前状态里没有,或者添加的错误当前状态已经有了。
可以让 t m p = x &amp; f 1 tmp=x \&amp;f_1 ,找出哪些病毒是这个补丁可以修复的,然后再让 x = t m p x^{\wedge }=tmp ,这样就把修复的病毒变成了 0 0
添加病毒的话直接让 x = f 2 x|=f_2 就可以了。

这道题算是让我大开眼界,网络流24题中没有网络流,想半天想不出来,神仙题目。。

code

#include<bits/stdc++.h>
using namespace std;
const int maxs=1<<21,maxm=105,inf=0x3f3f3f3f;

char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
	x=0;
	T f=1, ch=getchar();
	while (!isdigit(ch) && ch^'-') ch=getchar();
	if (ch=='-') f=-1, ch=getchar();
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
	x*=f;
}

template<typename T>inline void write(T x)
{
	if (!x) { putchar('0'); return ; }
	if (x<0) putchar('-'),x=-x;
	T num=0,ch[20];
	while (x) ch[++num]=x%10+48,x/=10;
	while (num) putchar(ch[num--]);
}

int tim[maxm],b1[maxm],b2[maxm],f1[maxm],f2[maxm];
inline bool check(int state,int id)
{
	if ((b1[id]|state)!=state) return false;
	if (b2[id]&state) return false;
	return true;
}

int dist[maxs],s,n,m;;
bool vis[maxs];
inline void spfa()
{
	memset(dist,0x3f,sizeof(dist));
	memset(vis,0,sizeof(vis));
	queue<int>q;
	q.push(s);dist[s]=0;
	while (!q.empty())
	{
		int x=q.front();
		q.pop();
		vis[x]=0;
		for (int i=1; i<=m; ++i)
		{
			if (!check(x,i)) continue;
			int y=x^(x&f1[i]);
			y|=f2[i];
			if (dist[y]>dist[x]+tim[i])
			{
				dist[y]=dist[x]+tim[i];
				if (!vis[y]) q.push(y),vis[y]=1;
			}
		}
	}
}

char a[maxm];
int main()
{
	read(n);read(m);
	s=(1<<n)-1;
	for (int i=1; i<=m; ++i)
	{
		read(tim[i]);
		scanf("%s",a);
		for (int j=0; j<n; ++j)
		{
			if (a[j]=='+') b1[i]+=1<<j;
			else if (a[j]=='-') b2[i]+=1<<j;
		}
		scanf("%s",a);
		for (int j=0; j<n; ++j)
		{
			if (a[j]=='-') f1[i]+=1<<j;
			else if (a[j]=='+') f2[i]+=1<<j;
		}
	}
	spfa();
	if (dist[0]==inf) puts("0");
	else write(dist[0]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/90748420
今日推荐