bzoj3037 创世纪

 

 

两种解法:

一、树状DP

 1 /*by SilverN*/
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 const int INF=100000000;
 9 const int mxn=1002000;
10 int hd[mxn],to[mxn],next[mxn];
11 int f[mxn],g[mxn],c[mxn];
12 int vis[mxn];
13 int cnt=0;
14 int n,p,eg;
15 void add_edge(int u,int v){
16     to[++cnt]=v;next[cnt]=hd[u];hd[u]=cnt;
17     return;
18 }
19 void dfs(int now){
20     vis[now]=1;
21     if(vis[c[now]])
22         p=now;
23     else dfs(c[now]);
24     return;
25 }
26 void solve(int now,int fa){
27     f[now]=1;g[now]=INF;vis[now]=1;
28     if(now==eg){
29         g[now]=0;
30     }
31     int u=hd[now];
32     while(u!=0){
33         if(to[u]!=fa && to[u]!=p)
34         {
35         //    printf("test msg4: now (%d)  to (%d) \n",now,to[u]);
36             solve(to[u],now);
37             g[now]+=min(f[to[u]],g[to[u]]);
38             g[now]=min(g[now],f[now]+f[to[u]]-1);
39             f[now]+=min(f[to[u]],g[to[u]]);
40         //    printf("test msg5: f[now]: %d  g[now]: %d \n",f[now],g[now]);
41         }
42         u=next[u];
43     }
44 }
45 int main(){
46     scanf("%d",&n);
47     int i,j;
48     for(i=1;i<=n;i++){
49         scanf("%d",&c[i]);
50         add_edge(c[i],i);//反向存边 
51     }
52     int ans=0;
53     for(i=1;i<=n;i++){
54         if(!vis[i]){
55         //    printf("test msg1: dfs(%d)\n",i);
56             dfs(i);
57         //    printf("test msg2: p(%d)\n",p);
58             eg=c[p];
59             solve(p,0);
60             int tmp=f[p];
61         //    printf("test msg3: tmp(%d)\n",tmp);
62             eg=0;
63             solve(p,0);
64             ans+=min(tmp,g[p]);
65         }
66     }
67     printf("%d\n",n-ans);
68 }

 

 

二、强行拓扑贪心

  AC

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 using namespace std;
 8 const int INF=100000000;
 9 const int mxn=1002000;
10 int in[mxn];
11 int ctl[mxn];
12 bool flag[mxn];
13 int n,cnt=0;
14 int ans=0;
15 int main(){
16     scanf("%d",&n);
17     int i,j;
18     for(i=1;i<=n;i++){
19         scanf("%d",&ctl[i]);
20         in[ctl[i]]++;//统计入度 
21     }
22     queue<int>q;
23     for(i=1;i<=n;i++){
24         if(!in[i]) q.push(i);
25     }
26     int tmp;
27     while(!q.empty()){
28         tmp=q.front();
29         q.pop();
30         if(!flag[tmp] && !flag[ctl[tmp]]){
31             ans++;
32             flag[ctl[tmp]]=1;
33             in[ctl[ctl[tmp]]]--;
34             if(!in[ctl[ctl[tmp]]]){//减后入度为0
35                 q.push(ctl[ctl[tmp]]);
36             }
37             
38         }
39         flag[tmp]=1;
40     }
41     for(i=1;i<=n;i++){
42         if(!flag[i]){
43             cnt=1;j=i;
44             flag[i]=1;
45             while(ctl[j]!=i){
46                 flag[ctl[j]]=1;//处理环 
47                 cnt++;
48                 j=ctl[j];
49             }
50             ans+=cnt/2;//环上一半的点可以投放 
51         }
52     }
53     printf("%d\n",ans);
54     return 0;
55 }

 

posted @ 2016-07-05 23:06  SilverNebula  阅读(312)  评论(0编辑  收藏  举报
AmazingCounters.com