UVA 11825 状态压缩DP

题目:https://cn.vjudge.net/contest/171116#problem/C

N台电脑,现在有N种服务,现在你可以在每台电脑终止一项服务,他和他相邻的电脑都会被关闭,如果一项服务在所有电脑都没运行,该项服务成功被破坏,问最多能破坏几种服务。

把该题转化成数学模型。把一个集合,分割成几个子集,每个子集中挑选几个数,组成集合,能够并成全集。

4

1

1 0

1 3

1 2

如0 1相连接,2 3相连,把 0 2破坏相同服务,即可破坏该服务,1 3破坏另一种,总共2种服务被破坏。

思路:

这道题首先把每个节点能够到达的节点都找出来。首先找到该节点相邻的节点,然后将相邻节点的相邻节点更新到当前节点当中。这里可以用二分法。s[i]初始化为1<<i,表示第i个节点。然后将其相邻节点temp用s[i]|=1<<temp放入,最后sta[i]表示第i个节点能到达的所有点。

接下来是状态转移方程,f[s]=max(f[s],f[s-s0]+1).s0表示s的子集,且能到达所有节点,so能够破坏一个服务。s-s0表示s中剩下的节点。f[s]表示集合s破坏的最多服务数。用s0模拟s的每一个子集,s0=(s0-1)&s就能模拟每个子集。

#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
#define maxn 1<<18
int sta[maxn],f[maxn];
int main()
{
	int n,m,i,j;
	int s[18], q = 1;
	while (~scanf("%d", &n) && n != 0)
	{
		for (i = 0; i < n; i++)
		{
			s[i] = 1 << i;
			scanf("%d", &m);
			while(m--)
			{
				int temp;
				scanf("%d", &temp);
				s[i] |= (1 << temp);//初始化第i个相邻的节点
			}
		}
		for (i = 0; i < (1 << n); i++)//sta[i]表示和i能够到达的所有相邻节点 dp[i]
		{	
			sta[i] = 0;
		for (j = 0; j < n; j++)
			if (i&(1 << j))
				sta[i] |= s[j];	
		}

		f[0] = 0; int all = (1 << n) - 1;
	

		for (int s = 1; s <= all; s++)//f[s]表示集合s能够破坏的最多服务数量
		{
			f[s] = 0;
			for (int s0 = s; s0; s0 = (s0 - 1)&s)
			{
				if (sta[s0] == all)
				f[s] = max(f[s], f[s^s0] + 1);//这里的解释是当S中的自己S0可以                                                          //的时候,这相对于补集+1
			}
		}
		printf("Case %d: %d\n", q++, f[all]);
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值