题目背景
一座城市,往往会被人们划分为几个区域,例如住宅区、商业区、工业区等等。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位小数),代表开店的最大利润。
输入输出样例
4 1 2 1 5 0 1 0 2 1 2 1 3 2
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;
}