• [BZOJ]2466: [中山市选2009]树


     题解:  $ n<=100 $  急忙叫队友是不是暴力题啊....

     qko:"好像我会O(n)"

     我:"好巧,我也会O(n)的,那就莽吧"

     四个状态 :

          $ dp1[x][0] $表示不摁且这个节点不亮的个数

          $ dp1[x][1] $表示不摁且这个节点亮的个数

          $ dp2[x][0] $表示摁且这个节点不亮的个数

          $ dp2[x][1] $表示摁且这个节点亮的个数

    #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=3e5+10;
    const double eps=1e-8;
    #define ll long long
    using namespace std;
    const int inf=1e6;
    struct edge{int t;edge*next;}e[MAXN<<1],*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;
    }
    
    int dp1[MAXN][2],dp2[MAXN][2];
    bool vis[MAXN];
    int n;
    void dfs(int x,int pre){
        int cnt1=0,cnt2=0;int ans1=0,ans2=0;
        int minn1=inf,minn2=inf;
        bool flag=0;int cnt=0;
        link(x){
    	if(j->t==pre)continue;
    	dfs(j->t,x);
    	flag=1;
    	if(vis[j->t])cnt++;
    	ans1+=min(dp1[j->t][1],dp2[j->t][1]);
    	if(dp2[j->t][1]<=dp1[j->t][1])cnt1++;
    	minn1=min(minn1,max(dp2[j->t][1],dp1[j->t][1])-min(dp2[j->t][1],dp1[j->t][1]));
    	ans2+=min(dp1[j->t][0],dp2[j->t][0]);
    	if(dp2[j->t][0]<=dp1[j->t][0])cnt2++;
    	minn2=min(minn2,max(dp2[j->t][0],dp1[j->t][0])-min(dp2[j->t][0],dp1[j->t][0]));
        }
        if(flag){
    //	cout<<cnt1<<" "<<cnt2<<endl;
    	if(cnt1%2==0)dp1[x][0]=ans1,dp1[x][1]=ans1+minn1;
    	else dp1[x][1]=ans1,dp1[x][0]=ans1+minn1;
    	if(cnt2%2==0)dp2[x][1]=ans2+1,dp2[x][0]=ans2+minn2+1;
    	else dp2[x][0]=ans2+1,dp2[x][1]=ans2+minn2+1;
    	//dp1[x][0]+=cnt;dp1[x][1]+=cnt;
        }
        else dp1[x][1]=dp2[x][0]=inf,dp2[x][1]=1,vis[x]=1;
        //cout<<x<<"::: "<<dp1[x][0]<<" "<<dp1[x][1]<<" "<<dp2[x][0]<<" "<<dp2[x][1]<<endl;
    }
    
    int main(){
        while(~scanf("%d",&n)&&n){
    	memset(h,0,sizeof(h));o=e;
    	memset(dp1,0,sizeof(dp1));memset(dp2,0,sizeof(dp2));
    	int x,y;
    	inc(i,2,n)x=read(),y=read(),add(x,y),add(y,x);
    	dfs(1,0);
    	printf("%d
    ",min(dp1[1][1],dp2[1][1]));
        }
        return 0;
    }

      

    2466: [中山市选2009]树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 1413  Solved: 613
    [Submit][Status][Discuss]

    Description

     图论中的树为一个无环的无向图。给定一棵树,每个节点有一盏指示灯和一个按钮。如果节点的按扭被按了,那么该节点的灯会从熄灭变为点亮(当按之前是熄灭的),或者从点亮到熄灭(当按之前是点亮的)。并且该节点的直接邻居也发生同样的变化。
     开始的时候,所有的指示灯都是熄灭的。请编程计算最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。

    Input

     输入文件有多组数据。
     输入第一行包含一个整数n,表示树的节点数目。每个节点的编号从1到n。 
     输入接下来的n – 1行,每一行包含两个整数x,y,表示节点x和y之间有一条无向边。
     当输入n为0时,表示输入结束。

    Output

    对于每组数据,输出最少要按多少次按钮,才能让所有节点的指示灯变为点亮状态。每一组数据独占一行。

    Sample Input

    3
    1 2
    1 3
    0

    Sample Output

    1

    HINT

    对于100%的数据,满足1 <= n <=100。

  • 相关阅读:
    【MariaDB】MariaDB的复制
    【MariaDB】MariaDB编译参数
    【MySQL】MySQL锁和隔离级别浅析二 之 INSERT
    【MySQL】查询使用临时表
    【MySQL】使用mysqlbinlog回滚
    ELK学习笔记(三)单台服务器多节点部署
    ELK学习笔记(二)-HelloWorld实例+Kibana介绍
    ELK学习笔记(六)分布式集群
    ELK学习笔记(四)SpringBoot+Logback+Redis+ELK实例
    ELK学习笔记(一)安装Elasticsearch、Kibana、Logstash和X-Pack
  • 原文地址:https://www.cnblogs.com/wang9897/p/10466571.html
Copyright © 2020-2023  润新知