• [BZOJ 1040] [ZJOI2008] 骑士 【基环+外向树DP】


    题目链接:BZOJ - 1040

    题目分析

    这道题目的模型就是一个图,不一定联通,每个连通块的点数等于边数。

    每个连通块都是一个基环+外向树。即树上增加了一条边。

    如果是树,就可以直接树形DP了。然而这是基环+外向树,需要先找到环上的一条边,记录这条边的两个端点 R1, R2,删掉这条边。

    然后分两种情况:一定不选R1;一定不选R2;对这两种情况分别做一次树形DP就可以了。

    答案加上这两种情况的答案的较大值。

    代码

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <cstdio>
    
    using namespace std;
    
    const int MaxN = 1000000 + 5;
    
    typedef long long LL;
    
    const LL INF = 99999999999999999;
    
    int n, R, R1, R2, Rt;
    int A[MaxN];
    
    LL Ans, Temp;
    LL F[MaxN][2];
    
    bool Visit[MaxN];
    
    struct Edge
    {
    	int u, v, t;
    	Edge *Next;
    } E[MaxN * 2], *P = E, *Point[MaxN];
    
    inline void AddEdge(int x, int y, int z) 
    {
    	++P; P -> u = x; P -> v = y; P -> t = z;
    	P -> Next = Point[x]; Point[x] = P;
    }
    
    inline LL gmax(LL a, LL b) {return a > b ? a : b;}
    
    void DFS(int x, int y) 
    {
    	Visit[x] = true;
    	for (Edge *j = Point[x]; j; j = j -> Next) 
    	{
    		if (j -> t == y) continue;
    		if (Visit[j -> v]) 
    		{
    			R1 = x; 
    			R2 = j -> v;
    			Rt = j -> t;
    		}
    		else DFS(j -> v, j -> t);
    	}
    }
    
    void Solve(int x, int y) 
    {
    	F[x][0] = 0; F[x][1] = A[x];
    	for (Edge *j = Point[x]; j; j = j -> Next)
    	{
    		if (j -> t == y || j -> t == Rt) continue;
    		Solve(j -> v, j -> t);
    		F[x][0] += gmax(F[j -> v][0], F[j -> v][1]);
    		F[x][1] += F[j -> v][0]; 
    	}
    	if (x == R) F[x][1] = -INF;
    }
    
    int main() 
    {
    	scanf("%d", &n);
    	int a;
    	for (int i = 1; i <= n; ++i) 
    	{
    		scanf("%d%d", &A[i], &a);
    		AddEdge(i, a, i);
    		AddEdge(a, i, i);
    	}
    	memset(Visit, 0, sizeof(Visit));
    	Ans = 0;
    	for (int i = 1; i <= n; ++i) 
    	{
    		if (Visit[i]) continue;
    		DFS(i, 0);
    		R = R1;
    		Solve(i, 0);
    		Temp = gmax(F[i][0], F[i][1]);
    		R = R2;
    		Solve(i, 0);
    		Temp = gmax(Temp, gmax(F[i][0], F[i][1]));
    		Ans += Temp;
    	}
    	printf("%lld
    ", Ans);
    	return 0;
    }
    

      

  • 相关阅读:
    网络时间校对
    OleVariant的本质
    GIT生成SSHKEY公钥放到服务器免密登录
    git 清除所有untracked file
    Linux命令 cat命令
    Linux如何通过命令查看日志文件的某几行(中间几行或最后几行)
    Git提交(PUSH)时记住密码 不用每次都输入密码
    arcgis10 arcmap10插件监控打开和保存文档
    arcmap10插件必看网页
    arcgis分解每一个部分为一个对象
  • 原文地址:https://www.cnblogs.com/JoeFan/p/4321290.html
Copyright © 2020-2023  润新知