【POI】T1 特工 szp
T1 特工szp
【问题描述】
Byteotian 中央情报局 (BIA) 雇佣了许多特工. 他们每个人的工作就是监视另一名特工.
Byteasar 国王需要进行一次秘密行动,所以他要挑选尽量多的信得过的特工. 但是这项任务是如此的机密以至于所有参加行动的特工都必须至少被另一名没有参加任务的特工所监视(就是说如果某个特工参加了行动,那么原先监视他的那些特工中至少要有一个没有参加进行动). 给出监视任务的详情,要求计算最多能有多少个特工参与其中.
【输入格式】
第一行只有一个整数, n – 特工的总数, 2 <= n <= 1000000. 特工从 1 到 n编号. 接下来 n 行每行一个整数 ak 表示特工 k 将要监视特工 ak , 1 <= k <= n, 1<= ak <= n, ak <> k.
【输出格式】
打印一个数,最多能有多少特工参加入这个任务.
【样例输入】
6
2
3
l
3
6
5
【样例输出】
3
Solution
来源:POI
①基环内向树+dp
每个点只有一条出边,基环内向树
将内向树先做了f[x][0]代表这个点不选,f[x][1]代表这个点选.转移(y为x的儿子):f[x][0]+=max(f[y][0],f[y][1]),f[i][1]=max(1+f[i][0]+f[y][0]-max(f[y][0],f[y][1]),f[i][1]);
做环的时候先随意选一个点(我选的第一个)割环为链,就是把第一个和最后一个点分开.
记g[x][0]为x选的个数,g[x][1]为x不选的个数
枚举最后一个点的情况(l为首个,r为末个),
0时,g[q[l]][0]=f[q[r]][1]+f[q[l]][0],g[q[l]][1]=f[q[r]][1]+f[q[l]][1];
1时,g[q[l]][0]=f[q[r]][0]+f[q[l]][0],g[q[l]][1]=f[q[r]][0]+max(f[q[l]][0]+1,f[q[l]][1]?f[q[l]][1]:1);
然后O(n)扫一遍环g[q[i]][0]=max(g[q[i-1]][0],g[q[i-1]][1])+f[q[i]][0],g[q[i]][1]=max(max(g[q[i-1]][0],g[q[i-1]][1])+f[q[i]][1],max(f[q[i]][0]+1,f[q[i]][1])+g[q[i-1]][0]);
注意特判当枚举最后一个点选的时候,如果!f[q[r]][1]即它没有子树(内向树),那么这次答案只能为g[q[r-1]][0]+1 else 每次答案max(g[q[r-1]][0],g[q[r-1]][1])
②贪心+拓扑序
又是鬼boy光勋考场上写的鬼算法
贪心思想,内向树中如果一个点它的儿子中有白点(不选),那么他肯定要选,因为他不选的话仅仅只会创造出一个黑点(它爸),而它爸还不如变白让爷爷变黑,对答案只增不少.
(题解)证明:若点i确定为白色,a[i]染白色也只能提供一个黑点,故a[i]染黑色不会差;若所有指向i的点均为黑色,则i只能是白色。
从度为零的点开始按拓扑序跑,将他爸标为黑点,爷爷度数--,度数为零入队.这样子连环也可以切开.然后还剩下一些单环(没有内向树),ans+=size/2.
Code
①
// <szp.cpp> - Thu Oct 6 08:17:54 2016 // This file is made by YJinpeng,created by XuYike's black technology automatically. // Copyright (C) 2016 ChangJun High School, Inc. // I don't know what this program is. #include <iostream> #include <vector> #include <algorithm> #include <cstring> #include <cstdio> #include <cstdlib> #include <cmath> #define MOD 1000000007 #define INF 1e9 #define IN inline #define RG register using namespace std; typedef long long LL; const int MAXN=1000010; inline int max(int &x,int &y) {return x>y?x:y;} inline int min(int &x,int &y) {return x<y?x:y;} inline int gi() { register int w=0,q=0;register char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')q=1,ch=getchar(); while(ch>='0'&&ch<='9')w=w*10+ch-'0',ch=getchar(); return q?-w:w; } int t;bool u[MAXN],k[MAXN];int f[MAXN][2],g[MAXN][2]; int fr[MAXN],to[MAXN],fa[MAXN],ne[MAXN],q[MAXN]; IN void add(int u,int v){ to[++t]=v;ne[t]=fr[u];fr[u]=t; } IN void dfs(int i){ k[i]=1; for(int j=fr[i],y;y=to[j],j;j=ne[j]) dfs(y),f[i][0]+=max(f[y][0],f[y][1]); for(int j=fr[i],y;y=to[j],j;j=ne[j]) f[i][1]=max(1+f[i][0]+f[y][0]-max(f[y][0],f[y][1]),f[i][1]); } int work(int l,int r,bool ty){ g[q[r-1]][0]=g[q[r-1]][1]=0; if(ty){ g[q[l]][0]=f[q[r]][1]+f[q[l]][0]; g[q[l]][1]=f[q[r]][1]+f[q[l]][1]; }else{ g[q[l]][0]=f[q[r]][0]+f[q[l]][0]; g[q[l]][1]=f[q[r]][0]+max(f[q[l]][0]+1,f[q[l]][1]?f[q[l]][1]:1); } for(int i=l+1;i<r;i++){ g[q[i]][0]=max(g[q[i-1]][0],g[q[i-1]][1])+f[q[i]][0]; g[q[i]][1]=max(max(g[q[i-1]][0],g[q[i-1]][1])+f[q[i]][1],max(f[q[i]][0]+1,f[q[i]][1])+g[q[i-1]][0]); } if(ty&&!f[q[r]][1])return g[q[r-1]][0]+1;//this case=0 return max(g[q[r-1]][0],g[q[r-1]][1]); } int main() { freopen("szp.in","r",stdin); freopen("szp.out","w",stdout); int n=gi(),ans=0; for(int i=1;i<=n;i++){ fa[i]=gi();add(fa[i],i); } while(1){ int x,tot=0,o; for(x=1;x<=n;x++)if(!k[x])break; if(x==n+1)break;u[q[tot=1]=x]=1; while(!u[fa[x]])x=fa[x],u[q[++tot]=x]=1; x=fa[x];for(o=tot;o;o--)if(q[o]==x)break; for(int i=1;i<=tot;i++)u[q[i]]=0;q[o-1]=q[tot]; for(int i=o;i<=tot;i++){ k[q[i]]=1; for(int j=fr[q[i]],y;y=to[j],j;j=ne[j]) if(y!=q[i-1])dfs(y),f[q[i]][0]+=max(f[y][0],f[y][1]); for(int j=fr[q[i]],y;y=to[j],j;j=ne[j]) if(y!=q[i-1])f[q[i]][1]=max(1+f[q[i]][0]+f[y][0]-max(f[y][0],f[y][1]),f[q[i]][1]); } ans+=max(work(o,tot,1),work(o,tot,0)); } printf("%d",ans); return 0; }
②xyk's
// <szp.cpp> - Thu Oct 6 08:07:12 2016 // This file is created by XuYike's black technology automatically. // Copyright (C) 2015 ChangJun High School, Inc. // I don't know what this program is. #include <iostream> #include <vector> #include <queue> #include <algorithm> #include <cstring> #include <cstdio> #include <cmath> using namespace std; typedef long long lol; int gi(){ int res=0,fh=1;char ch=getchar(); while((ch>'9'||ch<'0')&&ch!='-')ch=getchar(); if(ch=='-')fh=-1,ch=getchar(); while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar(); return fh*res; } const int MAXN=1000010; const int INF=1e9; int a[MAXN],d[MAXN]; bool vis[MAXN]; queue <int> q; int main(){ freopen("szp.in","r",stdin); freopen("szp.out","w",stdout); int n=gi(); for(int i=1;i<=n;i++){ a[i]=gi(); d[a[i]]++; } for(int i=1;i<=n;i++)if(!d[i])q.push(i); int ans=0; while(!q.empty()){ int x=q.front();q.pop(); vis[x]=1; if(vis[a[x]])continue; vis[a[x]]=1; ans++; if(!--d[a[a[x]]])q.push(a[a[x]]); } for(int i=1;i<=n;i++){ if(vis[i])continue; vis[i]=1;int sz=1; for(int j=a[i];j!=i;j=a[j]){vis[j]=1;sz++;} ans+=sz>>1; } printf("%d",ans); return 0; }