【BZOJ 1143】[CTSC2008]祭祀river

【链接】 我是链接,点我呀:)
【题意】

在这里输入题意

【题解】

这道题要求的是一个最长反链长度 (点集中任意两点之间都不能到达,且点的个数最多)

最长反链长度=最小链覆盖(也即最小路径覆盖)

最小路径覆盖可以用以下方法求得。

首先,把每个点都x分成两个点x1,x2
(x1放在左边,x2都放在右边,这样左右两边就都有n个点了
如果有一条边从x指向y。
那么就从左边的x1连一条边到右边的y2

然后在这样的规则下形成的二分图上。
我们做一下二分图匹配的最大匹配。
这样的结果就是路径不相交的最短路径覆盖了。
要怎么理解?

可以这样想。
一开始每个点单独成一条路径,ans=n条路径。
然后我们在做匹配的时候。
就是把两条路径合在一起。
会发现在这样的图上做匹配。就是把一条一条路径不相交的连起来。
每次做一下匹配,ans--
因为必然有条边长度更长的路径生成了。
(然后两条路径合在一起了,注意右边的点仍然表示那个点,不是虚构的,左边的点也是一样
(这样用匹配的定义,巧妙的把路径都串联起来了
但是这样我们做出来的是一个没有路径相交的覆盖。
最小路径覆盖是允许路径相交的。

那么我们在从左边往右边连边的时候。
先做一个floyd,求出两两之间的连通性。
这样,中间就能够之间跳过某些路径。
比如

1             5
  \         /
    3 - 4 
  /         \
2             6

这样的图
1和5因为可以通达,所以直接有边相连
而2-3-4-6也是相连的
因此,此时我们再套用上面不允许路径覆盖的方法,建立二分图
就能够找到1-3-4-5和2-3-4-6这两条有覆盖的路径了

【代码】

#include <bits/stdc++.h>
#define LL long long
#define rep1(i,a,b) for (int i = a;i <= b;i++)
#define rep2(i,a,b) for (int i = a;i >= b;i--)
#define all(x) x.begin(),x.end()
#define pb push_back
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;

const double pi = acos(-1);
const int dx[4] = {0,0,1,-1};
const int dy[4] = {1,-1,0,0};
const int N  = 100;

int n,m,g[N+10][N+10],G[N+10][N+10],pre[N+10];
bool flag[N+10];

bool dfs(int x){
    rep1(i,1,n)
        if (flag[i]==false && G[x][i]){
            flag[i] = true;
            if (pre[i]==0 || dfs(pre[i])){
                pre[i] = x;
                return true;
            }
        }
    return false;
}

int main(){
	#ifdef LOCAL_DEFINE
	    freopen("rush_in.txt", "r", stdin);
	#endif
    scanf("%d%d",&n,&m);
    rep1(i,1,m){
        int x,y;
        scanf("%d%d",&x,&y);
        g[x][y] = 1;
    }

    rep1(k,1,n)
        rep1(i,1,n)
            if (i!=k)
                rep1(j,1,n)
                    if (j!=k && j!=i){
                        g[i][j] |= (g[i][k] & g[k][j]);
                    }


    rep1(i,1,n)
        rep1(j,1,n)
            if (i!=j && g[i][j]){
                G[i][j] = 1;
            }

    int ans = n;
    rep1(i,1,n){
        memset(flag,0,sizeof flag);
        if (dfs(i)) ans--;
    }
    printf("%d\n",ans);
	return 0;
}

posted @ 2018-03-31 10:06  AWCXV  阅读(45)  评论(0编辑  收藏