CSP 训练赛0925

哎 还是太naiive
AB题都挺简单的敲了大概1.5H B题还拍了1H 然后我就zz了
不过还是挺细心的
最后检查发现可以为0 还有大小写问题

C题我开始一看 ??这题这么水吗 不就是对于每两个节点配对就行了嘛 还不用二分
不对我的思路一定有错!!!
然后看一眼大样例 对我一定想错了!
。。。。
然后最后几分钟 我 打了一波表 我的天啊 这不就是我想的做法吗

心态其实挺稳的 但是还是太naiive了

主要是以前有没看懂样例的经历 。。。

看不懂样例要仔细打表啊

3、拆网线(tree.pas/cpp)
【问题描述】
企鹅国的网吧们之间由网线互相连接,形成一棵树的结构。现在由于冬天到了,供暖部
门缺少燃料,于是他们决定去拆一些网线来做燃料。但是现在有 K 只企鹅要上网和别人联机
游戏,所以他们需要把这 K 只企鹅安排到不同的机房(两只企鹅在同一个机房会吵架),然
后拆掉一些网线,但是需要保证每只企鹅至少还能通过留下来的网线和至少另一只企鹅联机
游戏。
所以他们想知道,最少需要保留多少根网线?

解:
最大独立集
DFS或者从叶子节点开始贪心 或者DP
定义F[I][1/0]为 i的子树选i节点作为最大独立集合的点的最大边数

\(f[i][0]=\sum f[u][1]\)

\(f[i][1]=max(f[i][0]-f[u][1]+1);\)


code:

 

#include<stdio.h>
#include<bits/stdc++.h> 
using namespace std; 
#define maxnn 200100 
#define ll long long 
int las[maxnn],nex[maxnn],en[maxnn],tot; 
int n; 
int f[maxnn>>1][2];  
int T; 
int m; 
void add(int a,int b) { 
    en[++tot]=b; 
    nex[tot]=las[a]; 
    las[a]=tot; 
} 
void dfs(int v,int fa) 
{ 
    for(int i=las[v];i;i=nex[i]) 
    { 
        int u=en[i]; 
        if(u!=fa) 
        { 
            dfs(u,v); 
            f[v][0]+=f[u][1]; 
        } 
    } 
        for(int i=las[v];i;i=nex[i]) 
    { 
        int u=en[i]; 
        if(u!=fa) 
        { 
            f[v][1]=max(f[v][1],f[v][0]+f[u][0]-f[u][1]+1); 
        } 
    } 
     
} 
int main() { 
//  freopen("tree.in","r",stdin);
//  freopen("ooo","w",stdout);
    cin>>T; 
    int x,y,z; 
    while(T--) 
    { 
         for(int i=1;i<=n;i++) 
         f[i][0]=f[i][1]=0;
        scanf("%d%d",&n,&m);  
         for(int i=1;i<=tot;i++)
        {
            las[i]=0;
            nex[i]=0;
            en[i]=0;
        }
        tot=0;
        for(int i=1;i<n;i++)
       {
            scanf("%d",&x); 
            add(x,i+1); 
            add(i+1,x); 
        }
        dfs(1,1);
    
        int d=max(f[1][1],f[1][0]); 
        
        if(2*d>=m) 
        { 
            printf("%d\n",(m+1)/2); 
        } 
        else 
        { 
            printf("%d\n",d+m-2*d); 
        } 
    } 
} 

DFS版本
从叶子节点开始贪心

#include<stdio.h>
#include<bits/stdc++.h> 
using namespace std; 
#define maxnn 200100 
#define ll long long 
int las[maxnn],nex[maxnn],en[maxnn],tot; 
int n;  
int g[maxnn];
int T; 
int d=0;
int m; 
void add(int a,int b) { 
    en[++tot]=b; 
    nex[tot]=las[a]; 
    las[a]=tot; 
} 
void dfs(int v,int fa) 
{ 
    int fla=0;
    for(int i=las[v];i;i=nex[i]) 
    { 
        int u=en[i]; 
        if(u!=fa) 
        { 
            dfs(u,v); 
            if(!g[u])
            fla=1;
        } 
    } 
    if(fla)
    {
        d++;
        g[v]=1;
    }
} 
int main() { 
//  freopen("tree.in","r",stdin);
//  freopen("ooo","w",stdout);
    cin>>T; 
    int x,y,z; 
    while(T--) 
    { 
         for(int i=1;i<=n;i++) 
        g[i]=0;
        scanf("%d%d",&n,&m);  
         for(int i=1;i<=tot;i++)
        {
            las[i]=0;
            nex[i]=0;
            en[i]=0;
        }
        tot=0;
        d=0;
        for(int i=1;i<n;i++)
       {
            scanf("%d",&x); 
            add(x,i+1); 
            add(i+1,x); 
        }
        dfs(1,1);
        if(2*d>=m) 
        { 
            printf("%d\n",(m+1)/2); 
        } 
        else 
        { 
            printf("%d\n",d+m-2*d); 
        } 
    } 
} 

转载于:https://www.cnblogs.com/OIEREDSION/p/11588403.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值