大地的复苏
萌萌哒tangjz感应到OI村遭到了坏人Kinger Tangent的侵袭,急急忙忙的又赶了回来。 T_T
目前局势非常不好,Kinger Tangent正在施法引出岩浆不便移动,所以tangjz准备在一些地方布下防御塔。
现在的OI村有N个高地,编号分别为1~N。
萌萌哒tangjz布下的神の防御塔有着正义力量的加成,除了保护该地点外,还强制额外庇护另外一个地点,不过如果额外能庇护的地点已经受到保护了,就不能再该地点布置防御塔,否则会由于能量过大造成毁灭(不论主动被动,每个地点只能被庇护一次)。 >_<
第一行一个正整数N,表示OI村高地个数。
第二行有N个正整数,第i个正整数表示在第i个高地建立防御塔可以额外庇护的地点。
最多可以建的防御塔个数。
10
4 5 5 2 3 7 8 9 10 9
4
对于30%的数据:
对于60%的数据:
对于100%的数据:,每个地点都可以庇护一个其他的地点。
题目链接:http://codevs.cn/problem/2820/
拓扑排序+贪心。瞎搞了好久的动态规划。。。。。首先分析偶数链在环上的情况,如果贪心的选择链尾的最后一个点,发现选择到最后不会影响环上的点,如果是奇数链在环上,则最后一个选择的点一定会影响到环上的点,因此我们此时要对环进行继续贪心。如果在对环进行贪心的时候发现环上某个点还连着某一条链,如果是偶数链则没有影响,如果是奇数链,发现我们要是选了这个点,环上贡献加一,但是链上贡献减一,如果不选这个点,环上贡献减一,链上贡献加一,因此表面上看选不选这个点对答案没有影响,其实不然,如果选了这个点,环上这个点的下一个点就不能选了,如果不选这个点,这个点的下一个点还可以选。因此贪心的考虑我们不能选这个点。以上操作可以通过拓扑排序完美完成。
#include<bits/stdc++.h> #define N 2000000 int next[N],ind[N],vis[N],q[N]; int main() { int n,i,ans=0; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&next[i]); ind[next[i]]++; } int x,tot=0; for(i=1;i<=n;i++) if(ind[i]==0)q[++tot]=i; while(tot) { int now=q[tot--],nex=next[now]; vis[now]=true; if(!vis[nex]) { vis[nex]=true; ans++; if(!vis[next[nex]]&&(--ind[next[nex]]==0)) q[++tot]=next[nex]; } } for(i=1;i<=n;i++) if(!vis[i]) { int now=i,nex=i,c=1; vis[i]=true; while(1) { nex=next[nex]; if(nex==now) { ans+=c/2; break; } else { c++; vis[nex]=true; } } } printf("%d",ans); return 0; }