【luoguP1453】城市环路

来源:互联网 发布:java memcached 使用 编辑:程序博客网 时间:2024/06/09 19:40


题目背景

一座城市,往往会被人们划分为几个区域,例如住宅区、商业区、工业区等等。B市就被分为了以下的两个区域——城市中心和城市郊区。在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市中心。

题目描述

整个城市可以看做一个N个点,N条边的单圈图(保证图连通),唯一的环便是绕城的环路。保证环上任意两点有且只有2条路径互通。图中的其它部分皆隶属城市郊区。

现在,有一位名叫Jim的同学想在B市开店,但是任意一条边的2个点不能同时开店,每个点都有一定的人流量Pi,在该点开店的利润就等于该店的人流量Pi×K(K≤10000),K的值将给出。

Jim想尽量多的赚取利润,请问他应该在哪些地方开店?

输入输出格式

输入格式:

第一行一个整数N 代表城市中点的个数。城市中的N个点由0~N-1编号。

第二行N个正整数,表示每个点的人流量Pi(Pi≤10000)。

下面N行,每行2个整数A,B,表示A,B建有一条双向路。

最后一行一个实数K。

输出格式:

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

输入输出样例

输入样例#1:
41 2 1 50 10 21 21 32
输出样例#1:
12.0

说明

【数据范围】

对于20%的数据 N≤100.

对于50%的数据 N≤2000.

对于100%的数据 N≤100000(环上的点不超过2000个).



这题是相当的坑。。。

坑点相当恶心


先说一下题解:

这题其实是一道非常显然的DP

然后我们对于其他不在环上的点,可以发现可以树形DP预处理出来


然后然后就只剩下了一个环,

直接跑环形DP就好了


然后对于起点,选和不选要跑两遍


接下来说一下坑点:

如果有想到了O(环上的点^2)的算法,写完代码交了以后就会和我一样惊奇地发现


这题数据环上的点并没有保证不超过2000个!!!!!!!


我搞了一个晚上才发现这一点。。。。。。。


PS.这题蒟蒻发现和以前写的环形DP不一样,只需要一个起点跑一次就好了,仔细想想以后发现原来是以前的写过的环形DP出发点不一样会产生不同结果


代码:

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#include<cstdlib>#include<vector>#include<queue>#include<stack>using namespace std;typedef long long LL;typedef double DL;const int maxn = 200100;vector<int> e[maxn];queue<int> Q;DL p[maxn],a[maxn][2],f[maxn][2],k;bool vis[maxn],exist[maxn],flag = 0;int pre[maxn],stk[maxn],top,point[maxn],tot;int n;inline LL getint(){    LL ret = 0,f = 1;    char c = getchar();    while (c < '0' || c > '9')    {        if (c == '-') f = -1;        c = getchar();    }    while (c >= '0' && c <= '9')        ret = ret * 10 + c - '0',c = getchar();    return ret * f;}inline void find(int u,int fa){    vis[u] = 1;    stk[++top] = u;    for (int i = 0; i < e[u].size(); i++)    {        int v = e[u][i];        if (flag) return;        if (v == fa) continue;        if (vis[v])        {            while (stk[top] != v)            {                exist[stk[top]] = 1;                point[++tot] = stk[top--];            }            exist[stk[top]] = 1;            point[++tot] = stk[top--];            flag = 1;            return;        }        find(v,u);    }    stk[top] = 0;    top--;    return;}inline void init(int u,int fa){    a[u][1] = p[u] * k;    for (int i = 0; i < e[u].size(); i++)    {        int v = e[u][i];        if (v == fa) continue;        if (exist[v]) continue;        init(v,u);        a[u][0] += max(a[v][1],a[v][0]);        a[u][1] += a[v][0];    }}int main(){    n = getint();    for (int i = 1; i <= n; i++) p[i] = getint();    for (int i = 1; i <= n; i++)    {        int u = getint() + 1,v = getint() + 1;//        int u = getint(),v = getint();        e[u].push_back(v);        e[v].push_back(u);    }    scanf("%lf",&k);    memset(vis,0,sizeof(vis));    find(1,0);    memset(vis,0,sizeof(vis));    for (int i = 1; i <= n; i++)        init(i,0);    DL ans = 0;    n = tot;    f[1][0] = a[point[1]][0];    f[1][1] = 0;    for (int j = 2; j <= n; j++)    {        f[j][1] = f[j - 1][0] + a[point[j]][1];        f[j][0] = max(f[j - 1][1],f[j - 1][0]) + a[point[j]][0];    }    ans = max(ans,max(f[n][1],f[n][0]));    f[1][0] = 0;    f[1][1] = a[point[1]][1];    for (int j = 2; j <= n; j++)    {        f[j][1] = f[j - 1][0] + a[point[j]][1];        f[j][0] = max(f[j - 1][1],f[j - 1][0]) + a[point[j]][0];    }    ans = max(ans,f[n][0]);    printf("%.1lf",ans);    return 0;}


原创粉丝点击