bzoj2037 创世纪

来源:互联网 发布:1911淘宝交易 编辑:程序博客网 时间:2024/04/29 02:49

applepi手里有一本书《创世纪》,里面记录了这样一个故事……
上帝手中有着N 种被称作“世界元素”的东西,现在他要把它们中的一部分投放到一个新的空间中去以建造世界。每种世界元素都可以限制另外一种世界元素,所以说上帝希望所有被投放的世界元素都有至少一个没有被投放的世界元素能够限制它,这样上帝就可以保持对世界的控制。
由于那个著名的有关于上帝能不能制造一块连自己都不能举起的大石头的二律背反命题,我们知道上帝不是万能的,而且不但不是万能的,他甚至有事情需要找你帮忙——上帝希望知道他最多可以投放多少种世界元素,但是他只会O(2^N) 级别的算法。虽然上帝拥有无限多的时间,但是他也是个急性子。你需要帮助上帝解决这个问题。
Input
第一行是一个整数N,表示世界元素的数目。
第二行有 N 个整数A1, A2, …, AN。Ai 表示第i 个世界元素能够限制的世界元素的编号。
Output
一个整数,表示最多可以投放的世界元素的数目。
Sample Input
6

2 3 1 3 6 5

Sample Output
3

HINT

样例说明

选择2、3、5 三个世界元素即可。分别有1、4、6 来限制它们。

数据范围与约定

对于30% 的数据,N≤10。

对于60% 的数据, N≤10^5。

对于 100% 的数据,N≤10^6,1≤Ai≤N,Ai≠i。

和1040基本一样
题意求有向图中的最小支配集(单向支配)
做法
找环拆边:
对于一条边u,v。如果选u那么v一开始就被支配所以g[v]=0;
如果不选u,那么就正常的做一遍最小匹配
取最大值
f[i]代表选这个点时以I为根的子树的最小支配,g[i]代表这个点不选也被支配以I为根的子树时最小支配

#include<cstdio>#include<cstring>#include<utility>#include<algorithm>#include<iostream>#include<queue>#include<stack>#include<cmath>#include<cstdlib>#include<ctime>#define INF 0x3f3f3fusing namespace std;inline int read(){    char ch='*';    int f=1;    while(!isdigit(ch=getchar())) if(ch=='-') f=-1;    int num=ch-'0';    while(isdigit(ch=getchar())) num=num*10+ch-'0';    return num*f;}typedef long long ll;const int maxn = 2000005;struct edge{    int next,to;    bool ban;}e[maxn<<1];int cnt,h[maxn],v[maxn];int g[maxn],f[maxn],ans;int a[maxn],n,m,U,V,E;int p;int control;inline void add(int from,int to){    e[++cnt].next=h[from];    e[cnt].to=to;    h[from]=cnt;}void dfs(int x){    v[x]=1;    if(v[a[x]]) {        p=x;        return ;    }    dfs(a[x]);}void dp(int x,int fa,int ban){    f[x]=1;    g[x]=INF;    v[x]=1;    if(x==control) g[x]=0;    for(register int i=h[x];i;i=e[i].next)    {        if(i==ban||e[i].to==fa) continue;    //  if((i^1)==from) continue ;        dp(e[i].to,x,ban);        g[x]+=min(f[e[i].to],g[e[i].to]);        g[x]=min(g[x],f[x]+f[e[i].to]-1);        f[x]+=min(g[e[i].to],f[e[i].to]);    //  g[x]+=f[e[i].to];    }}       int main(){    n=read();    int u,vv;    for(register int i=1;i<=n;i++)    {        a[i]=read();        //add(u,i);        add(a[i],i);    }    for(register int i=1;i<=n;i++)    {        if(!v[i])               {            dfs(i);            //printf("%d %d %d \n",U,V,E);                      e[p].ban=1;            control=a[p];            dp(p,0,p);            control=0;            int temp=f[p];            dp(p,0,p);            ans+=min(temp,g[p]);        }    }    cout<<n-ans<<endl;    return 0;}
原创粉丝点击