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

    AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1143

    题目大意:

      给你n个点,点与点之间由有向边相连。如果u能到达v的话,那么他们就不能同时选。问最多选多少个点。

    [原题很强,可惜这里只有第一问,就变成大水题了...]

    首先当然先跑一遍Floyd跑个传递闭包。

    然后就是最大独立集了,最大独立集

    最长反链
    =最小路径覆盖数
    =n-二分图最大匹配

    然后就可以跑最大匹配了!

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    using namespace std;
    
    const int maxn=210;
    const int maxm=1010;
    const int INF=0x3f3f3f3f;
    
    struct Node{
        int data,next,low;
    }node[maxn*maxn*2+2*maxn];
    
    #define now node[point].data
    #define then node[point].next
    #define www node[point].low
    
    int n,m,cnt;
    int s,t,ans;
    int head[maxn],cur[maxn];
    int dis[maxn],que[maxn];
    bool f[maxn][maxn];
    
    void add(int u,int v,int w){
        node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++;
        node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++;
    }
    
    bool BFS(){
        memset(dis,-1,sizeof(dis));
        int H=0,T=1;que[1]=0;dis[s]=0;
        while(H<T){
            H++;
            for(int point=head[que[H]];point!=-1;point=then)
                if(www && dis[now]<0){
                    dis[now]=dis[que[H]]+1;
                    que[++T]=now;
                }
        }
        return dis[t]>0;
    }
    
    int dfs(int x,int low){
        if(x==t) return low;
        int Low;
        for(int &point=cur[x];point!=-1;point=then)
            if(www && dis[now]==dis[x]+1){
                Low=dfs(now,min(low,www));
                if(Low){
                    www-=Low,node[point^1].low+=Low;
                    return Low;
                }
            }
        return 0;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("1143.in","r",stdin);
        freopen("1143.out","w",stdout);
    #endif
        
        int u,v;
        
        scanf("%d%d",&n,&m);
        t=2*n+1;
        for(int i=s;i<=t;i++) head[i]=-1;
        for(int i=1;i<=n;i++) add(s,i,1),add(i+n,t,1);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            f[u][v]=true;
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    f[i][j]=f[i][j]|(f[i][k]&f[k][j]);
        
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(f[i][j] && i!=j) add(i,j+n,1);
        
        int flag;
        
        while(BFS()){
            for(int i=s;i<=t;i++) cur[i]=head[i];
            while(flag=dfs(s,INF))
                ans+=flag;
        }
        
        printf("%d",n-ans);
        return 0;
    }
    View Code
  • 相关阅读:
    [原]实例-简单设计&精简代码&复用代码
    [原创]实例-少用单例及降低耦合
    c#实现数据集合转换为csv文本
    [转]SqlServer索引的原理与应用
    [转]AngularJS:何时应该使用Directive、Controller、Service?
    [转]AngularJS移动开发中的坑汇总
    [转]Hibernate对象的三种状态
    [转]AngularJS Cookies Example
    [转]LESS CSS 框架简介
    [转]为ReportViewer导出的PDF文档加上水印
  • 原文地址:https://www.cnblogs.com/Robert-Yuan/p/5221805.html
Copyright © 2011-2022 走看看