zoukankan      html  css  js  c++  java
  • [NOI2013]快餐店(基环树dp)

    Analysis

    这是一道类似于基环树直径的题。显然答案为直径除以2。

    考虑暴力的做法,每次断一条环上边,然后找一下当前的直径,再取一个最小值即可。

    优化也很简答,维护四个数组 (h1,h2,g1,g2) 分别代表到左端点(环上第一个点)前缀最大值,到右端点(也是环上第一个点(嘿嘿想不到吧,只不过饶了一圈))后缀最大值,以及前缀最大答案和后缀最大答案,不动的看一下图就懂了。

    NOI2013.png

    然后我们枚举断边(i ightarrow i+1),然后拿(max(h1[i]+h2[i+1],max(g1[i],g2[i+1])))来更新答案,别忘了再和不在环上的链取最大。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll MAXN = 100005;
    const ll inf = 0x7f7f7f7f7f7f7f7f;
    template <typename T> void read(T &x) {
    	T f = 1;
    	char ch = getchar();
    	for (; '0' > ch || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    	for (x = 0; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    	x *= f;
    }
    ll n;
    vector<pair<ll, ll> > vec[MAXN];
    bool vis[MAXN], mark[MAXN];
    ll fa[MAXN];
    ll stk[MAXN], top;
    ll val[MAXN];
    ll s, t;
    ll dp[MAXN];
    ll ans;
    ll zsyy = inf;
    void zsy(ll x) {
    	vis[x] = true;
    	stk[++top] = x;
    	for (ll i = 0; i < (ll)vec[x].size(); i++) {
    		ll y = vec[x][i].first;
    		if (!mark[y]) continue;
    		val[top] = vec[x][i].second;
    		if (!vis[y]) zsy(y);
    	}
    }
    void dpp(ll x) {
    	ll fir = 0, sec = 0;
    	for (ll i = 0; i < (ll)vec[x].size(); i++) {
    		ll y = vec[x][i].first;
    		if (mark[y]) continue;
    		if (y == fa[x]) continue;
    		fa[y] = x;
    		dpp(y);
    		dp[x] = max(dp[x], dp[y] + vec[x][i].second);
    		if (dp[y] + vec[x][i].second > fir) {
    			sec = fir;
    			fir = dp[y] + vec[x][i].second;
    		} else if (dp[y] > sec) {
    			sec = dp[y] + vec[x][i].second;
    		}
    	}
    	ans = max(ans, sec + fir);
    }
    bool flag;
    void dfs(ll x) {
    	if (flag) return;
    	vis[x] = true;
    	for (ll i = 0; i < (ll)vec[x].size(); i++) {
    		ll y = vec[x][i].first;
    		if (y == fa[x]) continue;
    		if (flag) return;
    		if (vis[y]) {
    			flag = true;
    			s = x;
    			t = y;
    			return;
    		} else {
    			fa[y] = x;
    			dfs(y);
    		}
    		
    	}
    }
    ll h1[MAXN], h2[MAXN], g1[MAXN], g2[MAXN];
    int main() {
    	read(n);
    	for (ll i = 1; i <= n; i++) {
    		ll a, b, l;
    		read(a); read(b); read(l);
    		vec[a].push_back(make_pair(b, l));
    		vec[b].push_back(make_pair(a, l));
    	}
    	dfs(1);
    	while (s != t) {
    		mark[s] = 1;
    		s = fa[s];
    	}
    	mark[t] = 1;
    	memset(fa, 0, sizeof(fa));
    	memset(vis, 0, sizeof(vis));
    	for (ll i = 1; i <= n; i++) {
    		if (mark[i]) {
    			zsy(i);
    			break;
    		}
    	}
    	for (ll i = 1; i <= n; i++) {
    		if (mark[i]) {
    			dpp(i);
    		}
    	}
    	ll sum = val[1], cur = dp[stk[1]] + val[1];
    	for (ll i = 2; i <= top; i++) {
    		h1[i] = max(h1[i - 1], dp[stk[i]] + sum);
    		g1[i] = max(g1[i - 1], dp[stk[i]] + cur);
    		cur = max(cur, dp[stk[i]]) + val[i];
    		sum += val[i];
    	}
    	sum = val[top], cur = dp[stk[1]] + val[top];
    	for (ll i = top; i > 1; i--) {
    		h2[i] = max(h2[i + 1], dp[stk[i]] + sum);
    		g2[i] = max(g2[i + 1], dp[stk[i]] + cur);
    		cur = max(cur, dp[stk[i]]) + val[i - 1];
    		sum += val[i - 1];
    	}
    	for (ll i = 1; i <= top; i++) {//枚举断开 (i- -> i+1) 的边 
    		zsyy = min(zsyy, max(ans, max(h1[i] + h2[i + 1], max(g1[i], g2[i + 1]))));
    	}
    	printf("%.1lf", (double)zsyy / 2);
    	return 0;
    }
    
  • 相关阅读:
    hbase-0.92.1过滤器学习
    hbase-0.92.1表备份还原
    hbase-0.92.1集群部署
    hadoop hdfs 数据迁移到其他集群
    Kafka 1.0.0集群增加节点
    Kafka 1.0.0集群安装
    Hadoop 2.7.4 HDFS+YRAN HA删除datanode和nodemanager
    nodemanager 无法启动报错“doesn't satisfy minimum allocations”
    java Collections.sort的使用
    spring RestTemplate提交json格式数据
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14030680.html
Copyright © 2011-2022 走看看