题目描述
整个城市可以看做一个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位小数),代表开店的最大利润。
很明显是基环树的题。
首先最后的K是没有什么用的,因为我们的运算里只有加法,所以把K放到最后乘也不影响。我们先不把K算进去。
先考虑一棵树的情况。设dp(u,0/1)表示u的子树可以得到的最大利润,并且u是选(1)还是不选(0)。那么递推公式显然:
[dp[u][1]=sum_{v{in}son[u]} dp[v][0];\
dp[u][0]=sum_{v{in}son[u]} Max(dp[v][0],dp[v][1]);
]
初始化dp(u,0)=0,dp(u,1)=P(u)。目标状态为Max(dp(root,0/1))。
然而基环树就不那么简单。
朴素的做法就是枚举环上的每条边,把它断掉之后原图会变成一棵树,然后在树上做刚才的dp,得出对应的ans。枚举完所有边后去最大值即可。
但是我们发现断开一条边以后对于每个点选与不选没有影响。但是可以消除后效性。所以我们只需要断开任意一条边,然后分别以这条边的两个端点为根dp一遍即可。
时间复杂度为O(N)。
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 1000001
#define inf 0x3f3f3f3f
using namespace std;
struct edge{
int to,next;
edge(){}
edge(const int &_to,const int &_next){ to=_to,next=_next; }
}e[maxn<<1];
int head[maxn],k;
int n,val[maxn],ans;
double K;
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
inline void add(const int &u,const int &v){ e[k]=edge(v,head[u]),head[u]=k++; }
bool flag[maxn];
int s,t;
inline void getloop(){
for(register int i=0;i<k;i+=2){
int u=e[i].to,v=e[i^1].to;
if(flag[u]&&flag[v]){ s=u,t=v; return; }
flag[u]=flag[v]=true;
}
}
int dp[maxn][2];
bool vis[maxn];
void dfs(int u){
vis[u]=true,dp[u][1]=val[u],dp[u][0]=0;
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(vis[v]) continue;
dfs(v),dp[u][0]+=max(dp[v][0],dp[v][1]),dp[u][1]+=dp[v][0];
}
}
int main(){
memset(head,-1,sizeof head);
n=read();
for(register int i=1;i<=n;i++) val[i]=read();
for(register int i=1;i<=n;i++){
int u=read()+1,v=read()+1;
add(u,v),add(v,u);
}
scanf("%lf",&K);
getloop();
dfs(s),ans=max(ans,dp[s][0]);
memset(vis,false,sizeof vis);
dfs(t),ans=max(ans,dp[t][0]);
printf("%.1lf
",ans*K);
return 0;
}