• [BZOJ]2068: [Poi2004]SZP


    题解: 根据题目的特殊性 我们考虑基环树  对于非树边uv我们对深度较高的点分情况讨论 取或者不取  然后做个树dp就行了

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <stack>
    #include <queue>
    #include <cmath>
    #include <set>
    #include <map>
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define link(x) for(edge *j=h[x];j;j=j->next)
    #define inc(i,l,r) for(int i=l;i<=r;i++)
    #define dec(i,r,l) for(int i=r;i>=l;i--)
    const int MAXN=1e6+1100;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    const int inf=1e9;
    struct edge{int t;edge*next;}e[MAXN],*h[MAXN],*o=e;
    void add(int x,int y){o->t=y;o->next=h[x];h[x]=o++;}
    ll read(){
        ll x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    
    vector<pii>circle;
    bool vis[MAXN],c[MAXN];
    int n;
    int base,Base;
    int dp[MAXN][2],dp1[MAXN][2];
    
    void tarjan(int x,int y){
        circle.pb(mp(x,y));
    }
    
    void dfs(int x){
        vis[x]=1;
        link(x){
    	if(j->t==base)tarjan(x,base);
    	else if(!vis[j->t])dfs(j->t);
        }
    }
    
    void _dfs(int x){
        bool flag=0,flag1=0;int minn=inf;
        link(x){
    	if(j->t==base)continue;
    	_dfs(j->t);
    	flag1=1;
    	dp[x][0]+=max(dp[j->t][0],dp[j->t][1]);
    	if(dp[j->t][0]>=dp[j->t][1])flag=1;
    	if(j->t!=Base)minn=min(minn,dp[j->t][1]-dp[j->t][0]);
        }
        if(x==Base||flag)dp[x][1]=dp[x][0]+1;
        else dp[x][1]=max(0,dp[x][0]-minn+1);
    }
    
    void __dfs(int x){
        bool flag=0,flag1=0;int minn=inf;
        link(x){
    	if(j->t==base)continue;
    	__dfs(j->t);
    	flag1=1;
    	dp1[x][0]+=max(dp1[j->t][0],dp1[j->t][1]);
    	if(dp1[j->t][0]>=dp1[j->t][1])flag=1;
    	minn=min(minn,dp1[j->t][1]-dp1[j->t][0]);
        }
        if(flag)dp1[x][1]=dp1[x][0]+1;
        else dp1[x][1]=dp1[x][0]-minn+1;
    }
    
    int main(){
        n=read();
        inc(i,1,n){int x=read();add(x,i);}
        inc(i,1,n)if(!vis[i]){base=i;dfs(i);}
        int ans=0;
        for(int i=0;i<circle.size();i++){
    	int x=circle[i].first;int y=circle[i].second;
    	base=y;Base=x;
    	_dfs(y);__dfs(y);
    	ans+=max(dp[y][0],max(dp1[y][1],dp1[y][0]));
        }
        printf("%d
    ",ans);
    }
    

      

    2068: [Poi2004]SZP

    Time Limit: 20 Sec  Memory Limit: 162 MB
    Submit: 258  Solved: 118
    [Submit][Status][Discuss]

    Description

    Byteotian 中央情报局 (BIA) 雇佣了许多特工. 他们每个人的工作就是监视另一名特工. Byteasar 国王需要进行一次秘密行动,所以他要挑选尽量多的信得过的特工. 但是这项任务是如此的机密以至于所有参加行动的特工都必须至少被另一名没有参加任务的特工所监视( 就是说如果某个特工参加了行动,那么原先监视他的那些特工中至少要有一个没有参加进行动). 给出监视任务的详情,要求计算最多能有多少个特工参与其中.

    Input

    第一行只有一个整数, n – 特工的总数, 2 <= n <= 1000000. 特工从1 到 n编号. 接下来n行每行一个整数ak 表示特工k将要监视特工ak , 1 <= k <= n, 1 <= ak <= n, ak <> k.

    Output

    打印一个数,最多能有多少特工参加入这个任务.

    Sample Input

    6
    2
    3
    1
    3
    6
    5

    Sample Output

    3

    HINT

  • 相关阅读:
    JavaScript的BOM编程,事件-第4章
    C#获取程序目录
    e3商城_day05
    第三届中国云计算用户大会笔记和心得
    Android应用源码 概览
    电脑用bat脚本给手机批量自动安装apk文件 autoInstall.bat
    网上的很多Android项目源码有用吗?Android开发注意的地方。
    Android 简历 怎么写? 月薪10K,20K+, 怎么拿到面试?
    android 职业 转行
    我的Python学习之路(2)
  • 原文地址:https://www.cnblogs.com/wang9897/p/10455764.html
Copyright © 2020-2023  润新知