• 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) 
    ",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 
    ",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)
    ",i);
    56             dfs(i);
    57         //    printf("test msg2: p(%d)
    ",p);
    58             eg=c[p];
    59             solve(p,0);
    60             int tmp=f[p];
    61         //    printf("test msg3: tmp(%d)
    ",tmp);
    62             eg=0;
    63             solve(p,0);
    64             ans+=min(tmp,g[p]);
    65         }
    66     }
    67     printf("%d
    ",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
    ",ans);
    54     return 0;
    55 }
  • 相关阅读:
    json2jsoncpp 高级应用篇
    重载delete(operator delete)
    发布一个 json转c++ 的一个转换小程序(依赖jsoncpp 0.60)
    json2jsoncpp 关键代码分析2
    json2jsoncpp 基础应用篇
    linux下编译android版本的ffmpeg库
    win7系统下无线网卡共享本地网卡给移动设备上网
    使用事件冒泡原理控制菜单或浮层
    多条件Sql语句
    测试 数据库是否链接成功
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/5645368.html
Copyright © 2020-2023  润新知