• 6908. 【2020.11.30提高组模拟】关灯(light)/loj#3385. 「COCI 2020.11」Svjetlo


    题目描述

    https://loj.ac/p/3385

    题解

    dp维护路径线条,每次把当前的线条拆开加上新的

    设f[i,0/1,0/1/2]表示点i颜色为0/1,下面已固定了0/1/2个端点的答案

    分类讨论,注意可以多折一次来改变i和儿子的颜色,走完的儿子颜色必须为1

    一开始拓扑求出0的虚树,在上面dp即可

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define pd(x,y) (bg[x]<=bg[y] && ed[y]<=ed[x])
    #define min(a,b) (a<b?a:b)
    #define Min(a,b) a=min((a),(b))
    #define max(a,b) (a>b?a:b)
    #define ll long long
    #define file
    using namespace std;
    
    int b[500001],n,i,j,k,l,rt;
    int a[1000001][2],ls[500001],len;
    int f[500001][2][3];
    bool bz[500001];
    char st[500001];
    
    void init()
    {
    	static int d[500001],D[500001];
    	int h=0,t=0,i,j,k,l;
    	
    	memset(D,0,sizeof(D));
    	fo(i,1,n) for (j=ls[i]; j; j=a[j][1]) ++D[a[j][0]];
    	fo(i,1,n) if (b[i] && D[i]<=1) d[++t]=i;
    	while (h<t)
    	{
    		++h,bz[d[h]]=1;
    		for (i=ls[d[h]]; i; i=a[i][1])
    		{
    			--D[a[i][0]];
    			if (D[a[i][0]]==1 && b[a[i][0]]) d[++t]=a[i][0];
    		}
    	}
    }
    
    void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
    void dfs(int Fa,int t)
    {
    	int i,j,k,l,x;
    	int F[2][3];
    	
    	f[t][b[t]^1][0]=1;
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa && !bz[a[i][0]])
    	{
    		dfs(t,a[i][0]);x=a[i][0];
    		
    		if (!bz[x])
    		{
    			memset(F,1,sizeof(F));
    			fo(j,0,1)
    			{
    				Min(F[j^1][0],f[t][j][0]+f[x][1][0]+1);
    				Min(F[j][0],f[t][j][0]+f[x][0][0]+3);
    				Min(F[j][1],f[t][j][0]+f[x][1][1]);
    				Min(F[j^1][1],f[t][j][0]+f[x][0][1]+2);
    				Min(F[j][2],f[t][j][0]+f[x][0][2]+1);
    				Min(F[j^1][2],f[t][j][0]+f[x][1][2]+3);
    				
    				Min(F[j^1][1],f[t][j][1]+f[x][1][0]+1);
    				Min(F[j][1],f[t][j][1]+f[x][0][0]+3);
    				Min(F[j][2],f[t][j][1]+f[x][1][1]);
    				Min(F[j^1][2],f[t][j][1]+f[x][0][1]+2);
    				
    				Min(F[j^1][2],f[t][j][2]+f[x][1][0]+1);
    				Min(F[j][2],f[t][j][2]+f[x][0][0]+3);
    			}
    			memcpy(f[t],F,sizeof(F));
    		}
    	}
    	fo(i,0,1) fo(j,1,2) f[t][i][j]=min(f[t][i][j],f[t][i][j-1]);
    }
    
    int main()
    {
    	#ifdef file
    //	freopen("loj3385.in","r",stdin);
    	freopen("light.in","r",stdin);
    	freopen("light.out","w",stdout);
    	#endif
    	
    	scanf("%d",&n);
    	scanf("%s",st+1);
    	fo(i,1,n) b[i]=st[i]=='1';
    	fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j);
    	
    	memset(f,1,sizeof(f));
    	init();
    	fo(i,1,n) if (!bz[i]) break;rt=i;
    	dfs(0,rt);
    	printf("%d
    ",f[rt][1][2]);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    数据库基本操作
    守护线程
    线程使用的场景
    创建多线程
    用正则表达式去截取网页里文字的方法。参数为读取的网页源代码
    文章生成器,Split方法截取字符串。从硬盘读取文件,和向硬盘存储文件参考代码
    winform 阶段学习总结
    Windowform 窗体关联数据库存储,读取图片,参考代码
    windows form窗体应用程序,建一个记事本参考代码,重点是打开,保存,另存为
    js实现相册翻页,滚动,切换,轮播功能
  • 原文地址:https://www.cnblogs.com/gmh77/p/14076436.html
Copyright © 2020-2023  润新知