2020 camp day-3-C
题面
7-3 3C. 无向图定向
火山哥手里有一个n个点m条边的无向图。
现在,火山哥请你把无向图的每条边确定一个方向,使之成为一个DAG,并且最小化最长路的长度。
这里一条路径的长度指的是经过边的数量。
输入格式
第一行两个整数,,分别表示图的点数和边数。
接下来m行,每行两个正整数,,表示一条无向图。
输入数据保证无重边无自环,点编号从1开始。
1。
输出格式
一个整数,表示最短的最长路。
输入样例
3 3
1 2
2 3
1 3
5 4
1 2
2 3
3 4
4 5
输出样例
2
1
题解
结论:有向无环图的最长链点数等于最小的点集划分数使得每个点集中不存在两点有路径。
证明:
由于最长链上的两点必然不能属于同一个点集,所以点集划分数大于等于最长链长度。我们可以每次选出度为零的所有点划分在同一个点集中,若这些点之间有路径,则和他们出度为00矛盾,所以这样划分一定合法。同时,这样划分的集合数恰为原图的最长链长度。
我们其实变相证明了著名的dilworthdilworth定理:偏序集的最长链等于其最小反链划分。
然后直接枚举点集,状压预处理出其划分方式是否合法,然后枚举子集dp即可。
#include <cstdio> #include <cstring> #include <algorithm> #define RE register #define FOR(i,a,b) for(RE int i=a;i<=b;++i) #define ROF(i,a,b) for(RE int i=a;i>=b;--i) #define sc(n) scanf("%d",&n) #define ll long long #define p pair<int,int> using namespace std; const int maxv=17; const int maxn=(1<<17); int n,m,x,y; int mp[maxv][maxv],f[maxn],d[maxn]; void init() { FOR(k,0,(1<<n)-1) { f[k]=1; FOR(i,0,n-1) FOR(j,0,n-1) if(i!=j&&((k>>j)&1)&&((k>>i)&1)&&mp[i][j]) { f[k]=0; break; } } memset(d,63,sizeof(d)); d[0]=0; } int main() { sc(n);sc(m); FOR(i,1,m) sc(x),sc(y),mp[x-1][y-1]=mp[y-1][x-1]=1; init(); FOR(i,0,(1<<n)-1) for(RE int t=i;t;t=(t-1)&i) if(f[t])d[i]=min(d[i],d[i^t]+1); printf("%d\n", d[(1<<n)-1]-1); return 0; }