zoukankan      html  css  js  c++  java
  • Luogu P1453 城市环路|基环树+DP

    题目链接

    题目大意:
    一个 (n) 个点,(n) 条边的单圈图(保证图连通) 注:即基环树。现在要在图上开店,但是任意一条边的 (2) 个点不能同时开店,每个点都有一定的人流量,第 (i) 个点的人流量是 (p_i),在该点开店的利润就等于 (p_i imes k),其中 (k) 是一个常数。
    求最大利润。
    (1le nle 10^5)

    题目思路:
    假如是一颗树,那么我们很容易想到Dp。现在多了一条边,成为了基环树,问题便显得有些棘手。
    其实我们前文说基环树相当于环+树。那么我们先把环看作一个点,做树上DP。最后环上的每个点引出的边的答案都存在该点中。然后我们处理环。对于环上的每个点,有选与不选两种情况,有不同的权值。Dp即可。

    #include<bits/stdc++.h>
    #define N 100200
    using namespace std;
    int cc,to[N*2],net[N*2],fr[N*2],q[N*2],ri[N],f[N][2],g[N][2];
    int n,u,v,t,qt,p[N];bool vis[N],r[N];double k;
    void addedge(int u,int v)
    {
    	cc++;to[cc]=v;net[cc]=fr[u];fr[u]=cc;
    	cc++;to[cc]=u;net[cc]=fr[v];fr[v]=cc;
    }
    bool findr(int x)
    {
    	vis[x]=true;
    	q[++t]=x;
    	for (int i=fr[x];i;i=net[i])
    	{
    		if (vis[to[i]]&&q[t-1]!=to[i])
    		{
    			int tt=t;
    			while (q[tt]!=to[i])
    			{
    				ri[++qt]=q[tt];
    				r[q[tt]]=true;
    				tt--;
    			}
    			ri[++qt]=q[tt];
    			r[to[i]]=true;
    			t--;vis[x]=false;return true;
    		}
    		if (!vis[to[i]]) 
    		  if (findr(to[i])) 
    		  {
    		  	vis[x]=false;
    		  	return true;
    		  }
    	}
    	vis[x]=false;t--;
    	return false;
    }//找环
    void dfs(int x)
    {
    	vis[x]=true;f[x][1]=p[x];
    	for (int i=fr[x];i;i=net[i])
    	{
    		if (vis[to[i]]||r[to[i]]) continue;
    		dfs(to[i]);
    		f[x][0]+=max(f[to[i]][1],f[to[i]][0]);
    		f[x][1]+=f[to[i]][0];
    	}
    	vis[x]=false;
    }//树DP
    int main()
    {
    	scanf("%d",&n);
    	for (int i=0;i<n;i++)
    	{
    		scanf("%d",&p[i]);
    	}
    	cc=1;
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d%d",&u,&v);
    		addedge(u,v);
    	}
    	cin>>k;
    	findr(0);
    	for (int i=0;i<n;i++) 
    	{
    		if (r[i]) 
    			dfs(i);		
    	}
    //以下为环DP
    	g[1][1]=f[ri[1]][1];
    	int ans=0;
    	for (int i=2;i<qt;i++)
    	{
    		g[i][0]=max(g[i-1][0],g[i-1][1])+f[ri[i]][0];
    		g[i][1]=max(g[i-1][0],max(g[i-2][1],g[i-2][0]))+f[ri[i]][1];
    		ans=max(ans,max(g[i][0],g[i][1]));
    	}
    	g[1][0]=f[ri[1]][0];g[1][1]=0;
    	for (int i=2;i<=qt;i++)
    	{
    		g[i][0]=max(g[i-1][0],g[i-1][1])+f[ri[i]][0];
    		g[i][1]=max(g[i-1][0],max(g[i-2][1],g[i-2][0]))+f[ri[i]][1];
    		ans=max(ans,max(g[i][0],g[i][1]));
    	}
    	printf("%.1f
    ",k*ans);
    	return 0;
    }
    
  • 相关阅读:
    javascript 的继承实例
    [转载]编写高性能js
    弹出菜单
    xml xpath dta笔记
    jquery 学习笔记
    公用的css
    谷歌主页动画效果——利用视距暂留原理
    javascript 新知识
    ie6/7 bug大全
    javascript 原生实现 jquery live/delegate
  • 原文地址:https://www.cnblogs.com/fmj123/p/14604020.html
Copyright © 2011-2022 走看看