『状压DP·dilworth定理』BZOJ4160:Exclusive Access 2

该博客介绍了如何应用dilworth定理解决无向图定向成有向无环图,使最长路径最短的问题。通过解释dilworth定理的原理,即最长路径等于最小反链划分,提出了使用状压DP的方法来求解。文章还提到了最长反链与最小路径覆盖的关系,并给出了状态转移方程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

P r o b l e m \mathrm{Problem} Problem

给出 N 个点M 条边的无向图,定向得到有向无环图,使得最长路最短。

S o l u t i o n \mathrm{Solution} Solution

现在有一个定理叫做dilworth定理。具体的内容是这样的:

  • 最长路径(点的个数) = 最小反链划分
    一个集合为反链表示这个集合任意两点不能连通。最小反链划分表示整个图最少由多少个反链来划分。其中这张图是确定的,因此最小反链划分唯一。

由于这道题中,我们由于需要将图定向以后,得到最小反链划分的最小值,我们需要通过状压DP解决。

f [ i ] f[i] f[i]表示状态i是否是一个反链, g [ i ] g[i] g[i]表示对于状态i划分的最少反链数。

这样就有: g [ i ] = g [ i ′ ] + 1 , f [ i ] = 1 , i ′ ⊆ i g[i]=g[i']+1,f[i]=1,i'\subseteq i g[i]=g[i]+1,f[i]=1,ii.

当然还有一个结论是这样的:

  • 最长反链 = 最小路径覆盖
  • 其对应的例子就是导弹拦截的第二问,问多少个系统能够覆盖完所有导弹。

然后就有状态转移方程:

#include <map>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

int m;
int cnt = 0, n = 0;
int mp[50][50], t[50], f[1<<20], g[1<<20];

map<char,int>num;

int main(void)
{
	freopen("exclusive.in","r",stdin);
	freopen("exclusive.out","w",stdout);
	cin>>m;
	for (int i=1;i<=m;++i)
	{
		char a, b; cin>>a>>b;
		if (!num[a]) num[a] = ++n;
		if (!num[b]) num[b] = ++n;
		mp[num[a]][num[b]] = mp[num[b]][num[a]] = 1;
	}
	for (int i=0;i<1<<n;++i)
	{
		int t[50], k = 0;
		f[i] = 1;
		for (int j=1;j<=n;++j)
		    if ((i >> j-1) & 1) t[++k] = j;
		for (int u=1;u<k;++u)
		    for (int v=u+1;v<=k;++v)
		        if (mp[t[u]][t[v]]) f[i] = 0;
	}
	memset(g,30,sizeof f);
	g[0] = 0;
	for (int i=0;i<1<<n;++i)
	{
		if (f[i]) g[i] = 1;
		for (int j=i;j;j=(j-1)&i)      
		    if (f[j]) g[i] = min(g[i],g[i^j]+1);
	}
	if (g[(1<<n)-1] > 1e5) puts("Nie");
	else cout<<g[(1<<n)-1]-2<<endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值