『Exclusive Access 2 dilworth定理 状压dp』


Exclusive Access 2

Description

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

N ≤ 15, M ≤ 100

Input Format

第一行一个数M (1≤M≤100)。

接下来M行,每行两个大写字母(L 到 Z),最多出线15个不同的大写字母。每行的两个大写字母不会相同。

Output Format

第一行输出最长路最短的数值-1。

Sample Input

3
P Q
Q R
R P

Sample Output

1

解析

二分答案?想多了。

一个结论:有向无环图的最长链点数等于最小的点集划分数使得每个点集中不存在两点有路径。

证明:
由于最长链上的两点必然不能属于同一个点集,所以点集划分数大于等于最长链长度。

我们可以每次选出度为零的所有点划分在同一个点集中,若这些点之间有路径,则和他们出度为\(0\)矛盾,所以这样划分一定合法。同时,这样划分的集合数恰为原图的最长链长度。

我们其实变相证明了著名的\(dilworth\)定理:偏序集的最长链等于其最小反链划分。

然后直接枚举点集,状压预处理出其划分方式是否合法,然后枚举子集\(dp\)即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 16;
int n,m,a[N][N],p[1<<N],f[1<<N];
vector < pair<char,char> > Link;
map <char,int> Hash;
int main(void)
{
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
    {
        char c1,c2;
        cin >> c1 >> c2;
        Link.emplace_back(c1,c2);
        Hash[c1] = Hash[c2] = true;
    }
    map <char,int> :: iterator it;
    for (it=Hash.begin();it!=Hash.end();it++)
        it -> second = ++n;
    for ( auto e : Link )
        a[Hash[e.first]][Hash[e.second]] = a[Hash[e.second]][Hash[e.first]] = 1;
    memset( f , 0x3f , sizeof f );
    for (int S=1;S<1<<n;S++)
        for (int i=1;i<=n;i++)
            if ( S >> (i-1) & 1 )
                for (int j=i+1;j<=n;j++)
                    if ( S >> (j-1) & 1 )
                        p[S] |= a[i][j];
    f[0] = 0;
    for (int S=1;S<1<<n;S++)
        for (int T=S;T;T=S&(T-1))
            if ( p[T] == 0 )
                f[S] = min( f[S] , f[S^T] + 1 );
    printf("%d\n",f[(1<<n)-1]-2);
    return 0;
}


『Exclusive Access 2 dilworth定理 状压dp』

原文地址:https://www.cnblogs.com/Parsnip/p/11520262.html

时间: 2024-08-25 01:05:57

『Exclusive Access 2 dilworth定理 状压dp』的相关文章

『字符合并 区间dp 状压dp』

字符合并 Description 有一个长度为 n 的 01 串,你可以每次将相邻的 k 个字符合并,得到一个新的字符并获得一定分数.得到的新字符和分数由这 k 个字符确定.你需要求出你能获得的最大分数. Input Format 第一行两个整数n,k.接下来一行长度为n的01串,表示初始串. 接下来2^k行,每行一个字符ci和一个整数wi,ci表示长度为k的01串连成二进制后按从小到大顺序得到的第i种合并方案得到的新字符,wi表示对应的第i种方案对应获得的分数. 1<=n<=300,0<

【Codeforces】Gym 101173B Bipartite Blanket 霍尔定理+状压DP

题意 给一张$n\times m$二分图,带点权,问有多少完美匹配子集满足权值和大于等于$t$ 这里有一个结论:对于二分图$\mathbb{A}$和$\mathbb{B}$集合,如果子集$A \in \mathbb{A},B \in \mathbb{B}$,且$A,B$分别是完美匹配的子集,那么$A \cup B$属于一个完美匹配 有了这个结论之后,考虑单侧,枚举子集$S$,利用霍尔定理判定$S$是否是完美匹配,并通过dp转移状态,记录下单侧所有满足条件的权值和,然后两侧一起考虑累加得到答案 时

『公交线路 状压dp 矩阵乘法加速』

公交线路 Description 小Z所在的城市有N个公交车站,排列在一条长(N-1)km的直线上,从左到右依次编号为1到N,相邻公交车站间的距离均为1km. 作为公交车线路的规划者,小Z调查了市民的需求,决定按下述规则设计线路: 1.设共K辆公交车,则1到K号站作为始发站,N-K+1到N号台作为终点站. 2.每个车站必须被一辆且仅一辆公交车经过(始发站和终点站也算被经过). 3.公交车只能从编号较小的站台驶往编号较大的站台. 4.一辆公交车经过的相邻两个 站台间距离不得超过Pkm. 在最终设计

HDU 1565&amp;1569 方格取数系列(状压DP或者最大流)

方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 6206    Accepted Submission(s): 1975 Problem Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的

ZOJ3305Get Sauce 状压DP,

状压DP的题目留个纪念,首先题意一开始读错了,搞了好久,然后弄好了,觉得DFS可以,最后超时,修改了很久还是超时,没办法看了一下n的范围,然后觉得状压可以,但是没有直接推出来,就记忆化搜索了一下,可是一直错,莫名奇妙,然后没办法看了一下题解,发现了下面这个比较好的方法,然后按照这个方程去推,然后敲,也是WA了好多把,写的太搓了,没人家的清楚明了,唉~也算是给自己留个纪念,状压一直做的都不太好~唉~还好理解了, 参考了  http://blog.csdn.net/nash142857/articl

poj 2411 Mondriaan&#39;s Dream(状压DP)

Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12232   Accepted: 7142 Description Squares and rectangles fascinated the famous Dutch painter Piet Mondriaan. One night, after producing the drawings in his 'toilet series

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

HDU5816 Hearthstone(状压DP)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5816 Description Hearthstone is an online collectible card game from Blizzard Entertainment. Strategies and luck are the most important factors in this game. When you suffer a desperate situation an

HDU 4336 容斥原理 || 状压DP

状压DP :F(S)=Sum*F(S)+p(x1)*F(S^(1<<x1))+p(x2)*F(S^(1<<x2))...+1; F(S)表示取状态为S的牌的期望次数,Sum表示什么都不取得概率,p(x1)表示的是取x1的概率,最后要加一因为有又多拿了一次.整理一下就可以了. 1 #include <cstdio> 2 const int Maxn=23; 3 double F[1<<Maxn],p[Maxn]; 4 int n; 5 int main() 6