zoukankan      html  css  js  c++  java
  • luogu4298 [CTSC2008]祭祀

    题目链接

    problem

    给出一个有向无环图,找出最多的点,使他们两两之间不能到达。
    输出:
    最多找到的点数,
    输出一种方案,
    输出每个点是否存在一种方案使某个点可以被选出。

    Dilworth定理

    偏序集

    设R是集合A上的一个关系,R满足自反性,反对称性,传递性。那么就称R是集合A的偏序关系。

    集合A和关系R共同组成偏序集。

    例如,对于一个整数集合A,定义关系R为(le)。那么A和R就组成了一个偏序集,这个偏序集中任意两个元素都是可比的,因为任意两个整数都可以比较大小。但并不是所有偏序集中的任意两个元素都是可比的。

    全序集

    如果对于一个集合A和关系R,满足A中的任意两个元素都是可比的,就称A和R组成全序集。

    链与反链

    链就是全序集,全序集就是链。

    反链就是一个集合使得集合中的元素两两不可比。

    Dilworth定理

    偏序集中最小链划分中链的数量等于它最长反链的长度。

    solution

    如果两个点之间有连边,那么我们就认为这两个点是可比的。那这个题就是要求最长的反链长度。根据Dilworth定理,我们知道最长反链长度就是最小链覆盖的数量。

    所以建二分图跑最大匹配即可。

    注意在求链覆盖之前要先做一遍传递闭包。

    然后就解决了第一问。

    对于第二问,我们从右边没有被匹配的点开始dfs,从右边到左边时只走没有被匹配的边,从左到右时只走被匹配到的边。如果一个点左边没有被访问过右边被访问过,那么这个点就在所求反链里,否则不在。

    对于第三问,枚举一个点,删掉这个点以及所有和他有关系的点,如果答案比之前小恰好1,那么这个点就可能出现在反链里,否则不可能。

    code

    /*
    * @Author: wxyww
    * @Date:   2020-05-27 19:57:30
    * @Last Modified time: 2020-05-27 20:48:40
    */
    #include<cstdio>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<ctime>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int N = 1010;
    
    ll read() {
    	ll x = 0,f = 1;char c = getchar();
    	while(c < '0' || c > '9') {
    		if(c == '-') f = -1; c = getchar();
    	}
    	while(c >= '0' && c <= '9') {
    		x = x * 10 + c - '0'; c = getchar();
    	}
    	return x * f;
    }
    struct node {
    	int v,nxt,w;
    }e[N * N];
    int S,T,head[N],ejs = 1,cur[N];
    void add(int u,int v,int w) {
    	e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
    	e[++ejs].v = u;e[ejs].nxt = head[v];head[v] = ejs;e[ejs].w = 0;
    }
    int NOW,a[N][N],dep[N];
    int n,m,vis[N];
    queue<int>q;
    int check(int x) {
    	if(x > n) x -= n;
    	return x == NOW || a[x][NOW] || a[NOW][x];
    }
    
    int bfs() {
    	memset(dep,0,sizeof(dep));
    	dep[S] = 1;q.push(S);
    	while(!q.empty()) {
    		int u = q.front();q.pop();
    		for(int i = head[u];i;i = e[i].nxt) {
    			int v = e[i].v;
    			if(check(v)) continue;
    			if(!dep[v] && e[i].w) {
    				dep[v] = dep[u] + 1;q.push(v);
    			}
    		}
    	}
    	return dep[T];
    }
    int dfs(int u,int now) {
    	if(u == T) return now;
    	int ret = 0;
    	for(int &i = cur[u];i;i = e[i].nxt) {
    		int v = e[i].v;
    		if(check(v)) continue;
    		if(dep[v] == dep[u] + 1 && e[i].w) {
    			int k = dfs(v,min(now - ret,e[i].w));
    			e[i].w -= k;e[i ^ 1].w += k;
    			ret += k;
    			if(ret == now) return ret;
    		}
    	}
    	return ret;
    }
    int dinic() {
    	int ret = 0;
    	while(bfs()) {
    		memcpy(cur,head,sizeof(cur));
    		ret += dfs(S,10);
    	}
    	return ret;
    }
    int get(int u) {
    	vis[u] = 1;
    	for(int i = head[u];i;i = e[i].nxt) {
    		int v = e[i].v;
    		if(!e[i].w && !vis[v]) {
    			get(v);
    		}
    	}
    }
    int main() {
    	// freopen("1143/5.in","r",stdin);
    	n = read(),m = read();
    	for(int i = 1;i <= m;++i) {
    		int u = read(),v = read();
    		a[u][v] = 1;
    	}
    	for(int k = 1;k <= n;++k)
    		for(int i = 1;i <= n;++i)
    			for(int j = 1;j <= n;++j)
    				a[i][j] |= a[i][k] & a[k][j];
    	
    	S = n + n + 1,T = S + 1;
    	for(int i = 1;i <= n;++i) {
    		add(S,i,1);add(i + n,T,1);
    		for(int j = 1;j <= n;++j) {
    			if(a[i][j]) add(i,j + n,1);
    		}
    	}
    
    	int ans = n - dinic();
    	cout<<ans<<endl;
    
    	for(int i = head[T];i;i = e[i].nxt) {
    		if(!e[i].w)
    			get(e[i].v);
    	}
    	for(int i = 1;i <= n;++i) {
    		if(!vis[i] && vis[i + n]) printf("1");
    		else printf("0");
    	}
    	puts("");
    
    	for(int i = 1;i <= n;++i) {
    		NOW = i;
    		for(int i = 2;i <= ejs;i += 2) {
    			e[i].w = 1;e[i ^ 1].w = 0;
    		}
    		int tot = 0;
    		for(int j = 1;j <= n;++j) if(j != i && !a[j][i] && !a[i][j]) tot++;
    		// cout<<tot<<endl;
    		if(tot - dinic() != ans - 1) printf("0");
    		else printf("1");
    	}
    	return 0;
    }
    
  • 相关阅读:
    Notepad++
    pycharm
    pygame游戏开发-简介
    白月黑羽Python在线教程
    Selenium Web自动化 原理
    Web自动化
    Web自动化
    转:Android开发环境搭建
    Android系统架构说明介绍
    Enjoy Android
  • 原文地址:https://www.cnblogs.com/wxyww/p/luogu4298.html
Copyright © 2011-2022 走看看