码迷,mamicode.com
首页 > 其他好文 > 详细

BSOJ3760||洛谷P1453 城市环路 题解

时间:2017-06-17 17:10:44      阅读:180      评论:0      收藏:0      [点我收藏+]

标签:div   logs   没有   sample   树形dp   城市   else   编号   top   

城市环路

Description

  一座城市,往往会被人们划分为几个区域,例如住宅区、商业区、工业区等等。B市就被分为了以下的两个区域——城市中心和城市郊区。在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市中心。
  整个城市可以看做一个N个点,N条边的单圈图(保证图连通),唯一的环便是绕城的环路。保证环上任意两点有且只有2条路径互通。图中的其它部分皆隶属城市郊区。
  现在,有一位名叫Jim的同学想在B市开店,但是任意一条边的2个点不能同时开店,每个点都有一定的人流量Pi,在该点开店的利润就等于该店的人流量Pi×K(K≤10000),K的值将给出。
  Jim想尽量多的赚取利润,请问他应该在哪些地方开店?

Input

  第一行一个整数N 代表城市中点的个数。城市中的N个点由0~N-1编号。
  第二行N个正整数,表示每个点的人流量Pi(Pi≤10000)。
  下面N行,每行2个整数A,B,表示A,B建有一条双向路。
  最后一行一个实数K。

Output

  输出仅一个实数M,(保留1位小数),代表开店的最大利润。

Sample Input

4 1 2 1 5 0 1 0 2 1 2 1 3 2

Sample Output

12.0

Hint

【数据范围】
  对于20%的数据 N≤100.
  对于50%的数据 N≤2000.
  对于100%的数据 N≤100000.
 
↑以上是正经的题目描述XD
↓接下来是一点也不正经的题解啦
 
题目已经很明确了,这是个环,环上还有树。
就像这样:
技术分享
 
乍一看会很麻烦对吧......那么我们先来考虑一下比较简单的情况。假如这一开始就只是个环呢?
那很简单啊,只要随便找个点开始,选择它跑一圈,不选它再跑一圈,取个最大值就行了嘛。
那么,加上树有什么影响呢?
没有。对,没有。只要提前把这个点引出去的树处理好就行了。
也就是说,只需要先对这棵子树进行一次动态规划,然后把这里能取到的最大值当做这个点的权值,这题就成了环形DP裸题啦23333。
 
主要流程:
①:Tarjan法先找出图中唯一的环。
②:枚举环上的每个点进行树形DP。
③:跑一遍环上DP。
 
听说这个东西好像叫环套树来着...去看了看其他几道环套树都好可怕啊QAQ
 
AC Code:
技术分享
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stack>
#include<iostream>
#include<algorithm>
using namespace std;
inline const int Read()
{
    int Num=0,Sgn=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch==-)Sgn=-1;ch=getchar();}
    while(isdigit(ch)){Num=(Num<<1)+(Num<<3)+ch-0;ch=getchar();}
    return Num*Sgn;
}

struct Edge
{
    int Next,To;
}e[200005];
int h[200005]={0},Cnt=0;
void Addedge(int x,int y){e[++Cnt]=(Edge){h[x],y}; h[x]=Cnt;}
int a[200005]={0};
double K;
int N;

int Scnt=0;
int DFN[200005]={0},Lowlink[200005]={0};
int Cir[200005]={0},Belong[200005]={0},Prt[200005]={0};
int f[200005][2]={0},g[200005][2]={0};

stack<int>Sta;

void Tarjan(int x)
{
    Scnt++;
    DFN[x]=Scnt; Lowlink[x]=Scnt;
    Sta.push(x);
    for(int i=h[x];i;i=e[i].Next)
    {
        int y=e[i].To;
        if(!DFN[y])
        {
            Prt[y]=x;
            Tarjan(y);
            Lowlink[x]=min(Lowlink[x],Lowlink[y]);
        }
        else if(Prt[x]!=y)
          Lowlink[x]=min(Lowlink[x],DFN[y]);
    }
    if(Lowlink[x]==DFN[x])
    {
        if(Sta.top()==x)
        {
            Sta.pop();
            return;
        }
        int t;
        do
        {
            t=Sta.top(); Sta.pop();
            Cir[++Cir[0]]=t;
            Belong[t]=1;
        }while(t!=x);
    }
}

void DFS(int x)
{
    f[x][0]=0; f[x][1]=a[x];
    for(int i=h[x];i;i=e[i].Next)
    {
        int y=e[i].To;
        if(Prt[x]!=y&&!Belong[y])
        {
            Prt[y]=x;
            DFS(y);
            f[x][0]+=max(f[y][1],f[y][0]);
            f[x][1]+=f[y][0];
        }
    }
}

int main()
{
    N=Read();
    for(int i=1;i<=N;i++)
      a[i]=Read();
    for(int i=1;i<=N;i++)
    {
        int Tx=Read(),Ty=Read();
        Addedge(Tx+1,Ty+1); Addedge(Ty+1,Tx+1);
    }
    scanf("%lf",&K);
    Tarjan(1);
    int M=Cir[0];
    memset(Prt,0,sizeof(Prt));
    for(int i=1;i<=M;i++)
      DFS(Cir[i]);
    for(int i=1;i<=M;i++)
    {
        g[i][0]=f[Cir[i]][0];
        g[i][1]=f[Cir[i]][1];
    }
    
    f[2][0]=g[1][0]+g[2][0];
    f[2][1]=g[1][0]+g[2][1];
    for(int i=3;i<=M;i++)
    {
        f[i][1]=f[i-1][0]+g[i][1];
        f[i][0]=max(f[i-1][0],f[i-1][1])+g[i][0];
    }
    int Ans=0;
    Ans=max(f[M][1],max(Ans,f[M][0]));
    f[2][0]=g[1][1]+g[2][0];
    f[2][1]=-0x3f3f3f3f;
    for(int i=3;i<=M;i++)
    {
        f[i][0]=max(f[i-1][0],f[i-1][1])+g[i][0];
        f[i][1]=f[i-1][0]+g[i][1];
    }
    Ans=max(Ans,f[M][0]);
    printf("%.1lf\n",(double)Ans*K);
    return 0;
}
View Code

 

一开始忘了环形要跑两遍...真是⑨一般的错误啊(笑)

BSOJ3760||洛谷P1453 城市环路 题解

标签:div   logs   没有   sample   树形dp   城市   else   编号   top   

原文地址:http://www.cnblogs.com/Kaga/p/7040348.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!