bzoj1143

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1143

首先用传递闭包,知道一个点是否可以到达另一个点,即mp[i][j]==1表示i可以到j;mp[i][j]==0表示i不可以到j。

然后变成求有向无环图的最大独立集。

这是个经典问题,要变成二分图。

将每个点拆成两个点x和y

如果有边i->j,那么连边ix->jy。

然后求二分图的最大匹配,N-最大匹配就是答案。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b)  for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

const DB EPS=1e-9;
inline int sgn(DB x){if(abs(x)<EPS)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

inline int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }
inline LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }

const int maxN=100;

int N,M;
int mp[maxN+10][maxN+10];

int first[maxN+100],now;
struct Tedge{int v,next;}edge[maxN*maxN+10000];
int ans;

inline void addedge(int u,int v)
  {
      now++;
      edge[now].v=v;
      edge[now].next=first[u];
      first[u]=now;
  }

int vis[maxN+100];
int form[maxN+100];

inline int DFS(int u)
  {
      int i,v;
      vis[u]=1;
      for(i=first[u],v=edge[i].v;i!=-1;i=edge[i].next,v=edge[i].v)
        if(!form[v] || (!vis[form[v]] && DFS(form[v])))
          {
              form[v]=u;
              return 1;
          }
      return 0;
  }

int main()
  {
      freopen("bzoj1143.in","r",stdin);
      freopen("bzoj1143.out","w",stdout);
      int i,j,k;
      N=gint();M=gint();
      re(i,1,M){int u=gint(),v=gint();mp[u][v]=1;}
      re(k,1,N)re(i,1,N)re(j,1,N)if(i!=k && j!=k && i!=j && mp[i][k] && mp[k][j]) mp[i][j]=1;
      mmst(first,-1);now=-1;
      re(i,1,N)re(j,1,N)if(mp[i][j])addedge(i,j);
      ans=0;
      re(i,1,N)
        {
            re(j,1,N)vis[j]=0;
            ans+=DFS(i);
        }
        printf("%d\n",N-ans);
        return 0;
    }

时间: 2024-12-21 03:38:27

bzoj1143的相关文章

BZOJ1143 [CTSC2008] 祭祀river

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1143 题目大意: 给你n个点,点与点之间由有向边相连.如果u能到达v的话,那么他们就不能同时选.问最多选多少个点. [原题很强,可惜这里只有第一问,就变成大水题了...] 首先当然先跑一遍Floyd跑个传递闭包. 然后就是最大独立集了,最大独立集 最长反链=最小路径覆盖数=n-二分图最大匹配 然后就可以跑最大匹配了! #include<cstdio> #include<cstri

【bzoj1143】[CTSC2008]祭祀river

题目描述 在遥远的东方,有一个神秘的民族,自称Y族.他们世代居住在水面上,奉龙王为神.每逢重大庆典, Y族都会在水面上举办盛大的祭祀活动.我们可以把Y族居住地水系看成一个由岔口和河道组成的网络.每条河道连接着两个岔口,并且水在河道内按照一个固定的方向流动.显然,水系中不会有环流(下图描述一个环流的例子). 由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行.出于对龙王的尊重,这些祭祀地点的选择必须非常慎重.准确地说,Y族人认为,如果水流可以从一个祭祀点流到另外一个祭祀点,那么祭祀就会失去它

【BZOJ1143】【CTSC2008】祭祀river 传递闭包、最大点独立集(网络流写的)

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43225427"); } 题意:那个图不要看,给的没错,是有向无环图(拓扑) 题解: 对于每两点,都有一个关系---->如果传递闭包后a能到b,那么两者只能选一个. 完事了. 代码: #include <queue> #include

[BZOJ1143]祭祀

这题水很深... 题目给了一个有向无环图,要求找出最多的点且这些点中不存在两个点使得它们之间有路径 如果$x$能到$y$,那么$x,y$只能选其中一个,所以连上一条边$(x,y)$不改变答案(其实是在找传递闭包) 这时可以转化一下题目:给出一个偏序集,问最大反链长度 Dilworth定理:偏序集的最大反链长度=偏序集划分为链的最少链数 这里有一篇博客写得非常好,这里引用+删减 用数学归纳法 假设偏序集为$S$且$n=\left|S\right|$,对于$n\geq 2$,假设对所有的$m\lt

BZOJ 刷题记录 PART 4

[BZOJ1143]CTSC的题目...先用floyed传递闭包,然后直接上匈牙利算法. [BZOJ1452]从未写过的二维树状数组.好像很简单.. struct two_bit { int f[305][305]; inline void add(int x,int z,int A) { for (;x<=n;x+=L(x)) for (int y=z;y<=m;y+=L(y)) f[x][y]+=A; } inline int ask(int x,int z) { int ans=0; f

-----------------------【有趣の题目】-----------------------

做过的,有意义多次看的,有趣的题目整合包 图论相关: [BZOJ-3308]九月的咖啡店   线性筛素数+有趣的处理+最大费用最大流 [BZOJ-4205]卡牌配对   线性筛素数+最大流+玄学的效率 [BZOJ-2095]Bridge   混合图欧拉回路 [BZOJ-1797]Mincut 最小割    最大流+Tarjan+缩点+分类讨论 [BZOJ-2879]美食节    最小费用最大流+拆点+动态建图 [BZOJ-1061]志愿者招募   线性规划转最小费用最大流 [BZOJ-2118]

关于最大匹配,最小点覆盖,最少路径覆盖和最大独立集的总结

(1)二分图的最大匹配 匈牙利算法 (2)二分图的最小点覆盖 二分图的最小点覆盖=二分图的最大匹配 求最小点覆盖:从右边所有没有匹配过的点出发,按照增广路的“交替出现”的要求DFS.最终右边没有访问过的点和左边访问过的点组成最小点覆盖. 证明见这里 (3)二分图的最少边覆盖 二分图的最少边覆盖=点数-二分图的最大匹配 证明: 先贪心选一组最大匹配的边放进集合,对于剩下的没有匹配的点,随便选一条与之关联的边放进集合,那么得到的集合就是最小边覆盖. 所以有:最小边覆盖=最大匹配+点数-2*最大匹配=

20160327~20160402

蒟蒻太弱了,一星期刷这么少. 20160329: 1.bzoj1087 http://www.lydsy.com/JudgeOnline/problem.php?id=1087 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 using namespace std; 6 7 long long x

bzoj刷题(shui)记录

放假刷了一个月的水题,集中写一下题解吧. bzoj1858:线段树随便维护一下. code bzoj2705:莫比乌斯反演裸题. code bzoj1202:并查集,但是我写了一种跟floyd很像的奇怪的东西. code bzoj1072:暴力. bzoj2431:dp f[i][j]=sum(f[i-1],[k]) code bzoj3505:组合数学. code bzoj1058:两棵平衡树. code bzoj1922:维护两个距离,然后更新答案. code bzoj1009:之前写过题解