51nod 1325 两棵树的问题 最大权闭合子图

来源:互联网 发布:詹姆斯去年总决赛数据 编辑:程序博客网 时间:2024/05/21 09:45

题意

有两颗各含N个点的无根树,每棵树中点分别被编号为0,1,2,….,N-1;注意两棵树并不保证同构。
另外给一个N长的整数数组Score[],记录N个编号的得分,Score中的每个元素可正可负。
问题的任务是寻找 集合{0,1,2,3,4,…,N-1}的一个最优子集subset,要求满足以下条件:
1)在第一棵树中,subset中包含的编号对应的点能构成一个连通的子图;即去掉这棵树中所有subset中不包含的点后,剩下的点依然是一棵连通的树。
2)在第二棵树中,subset中包含的编号对应的点也能构成一个连通的子图;
3)使subset包含编号的总得分尽可能的大;即SUM{ Score[i] | i∈subset }能取到尽可能大的值。
输出这个subset包含编号的总分的最大值。
2<=N<=50,-1000<=Score[i]<=1000

分析

首先我们可以枚举两棵子树的根,然后继续搞事。
注意到如果选了点x,那么在每一棵树上x到根路径上的所有点都要选。我们可以把这看成一个限制关系,如果选了x就一定要选x在两棵树中的父亲。然后直接上最大权闭合子图即可。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int N=55;const int inf=1000000000;int n,cnt,last[N],ls1[N],ls2[N],cur[N],dis[N],s,t,val[N];struct edge{int to,next,c;}e[N*N*10];queue<int> que;int read(){    int x=0,f=1;char ch=getchar();    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}void addedge(int u,int v,int c){    e[++cnt].to=v;e[cnt].c=c;e[cnt].next=last[u];last[u]=cnt;    e[++cnt].to=u;e[cnt].c=0;e[cnt].next=last[v];last[v]=cnt;}void build(int x,int fa,int op){    if (fa) addedge(x,fa,inf);    if (op==1)    {        for (int i=ls1[x];i;i=e[i].next) if (e[i].to!=fa) build(e[i].to,x,op);    }    else    {        for (int i=ls2[x];i;i=e[i].next) if (e[i].to!=fa) build(e[i].to,x,op);    }}bool bfs(){    for (int i=s;i<=t;i++) dis[i]=0;    while (!que.empty()) que.pop();    dis[s]=1;que.push(s);    while (!que.empty())    {        int u=que.front();que.pop();        for (int i=last[u];i;i=e[i].next)            if (e[i].c&&!dis[e[i].to])            {                dis[e[i].to]=dis[u]+1;                if (e[i].to==t) return 1;                que.push(e[i].to);            }    }    return 0;}int dfs(int x,int maxf){    if (x==t||!maxf) return maxf;    int ret=0;    for (int &i=cur[x];i;i=e[i].next)        if (e[i].c&&dis[e[i].to]==dis[x]+1)        {            int f=dfs(e[i].to,min(e[i].c,maxf-ret));            e[i].c-=f;            e[i^1].c+=f;            ret+=f;            if (maxf==ret) break;        }    return ret;}int dinic(){    int ans=0;    while (bfs())    {        for (int i=s;i<=t;i++) cur[i]=last[i];        ans+=dfs(s,inf);    }    return ans;}int main(){    n=read();    for (int i=1;i<=n;i++) val[i]=read();    for (int i=1;i<n;i++)    {        int x=read()+1,y=read()+1;        e[++cnt].to=y;e[cnt].next=ls1[x];ls1[x]=cnt;        e[++cnt].to=x;e[cnt].next=ls1[y];ls1[y]=cnt;    }    for (int i=1;i<n;i++)    {        int x=read()+1,y=read()+1;        e[++cnt].to=y;e[cnt].next=ls2[x];ls2[x]=cnt;        e[++cnt].to=x;e[cnt].next=ls2[y];ls2[y]=cnt;    }    s=0;t=n+1;int tmp=cnt;    if (!(tmp&1)) tmp++;    int ans=0;    for (int r1=1;r1<=n;r1++)        for (int r2=1;r2<=n;r2++)        {            int sum=0;cnt=tmp;            for (int i=s;i<=t;i++) last[i]=0;            for (int i=1;i<=n;i++)                if (val[i]>0) sum+=val[i],addedge(s,i,val[i]);                else addedge(i,t,-val[i]);            build(r1,0,1);            build(r2,0,2);            sum-=dinic();            ans=max(ans,sum);        }    printf("%d",ans);    return 0;}
阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 男人体虚怎么补 身体虚喝什么汤好 多汗体虚 体虚体寒怎么办 产后体虚吃什么补品好得快 体虚怕冷 产后身体虚怎么办 体虚容易出汗 身体虚怎么食补 体虚乏力是怎么回事 小孩体虚吃什么好 肾会阴阳两虚吗 男性身体虚怎么调理 内热体虚 体虚感冒 产后体虚怎么办 肾阴阳双虚 身体虚吃什么调理 身体气血虚的表现 体虚吃什么水果 产后体虚的症状 为什么体虚 男人体虚多汗怎么办 身体虚怎样调理 男人体虚喝什么汤好 体寒体虚吃什么好 身体虚热怎么办 头晕体虚 体虚食补 体虚心慌 身体虚吃什么补品 身体虚 怎么调理 孕妇身体虚吃什么好 女人身体虚 体虚会失眠吗 体虚的人喝什么茶好 男人身体虚吃什么补身体 产妇身体虚吃什么好得快 身体虚弱怎么调理 生完孩子身体虚怎么办 指甲长得快说明体虚