首页 > 其他 > 详细

bzoj4873-最大权闭合子图

时间:2019-08-17 22:32:10      阅读:95      评论:0      收藏:0      [点我收藏+]
技术分享图片
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<string>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<iomanip>
  8 #include<queue>
  9 using namespace std;
 10 namespace Moxing {
 11     const int N=105,M=1005;
 12     const int inf=0x3f3f3f3f;
 13     int n,m,a[N],mp[N][N],id[N][N],idw[M],ict,S,T,cnt=1,last[30303];
 14     long long sum;
 15     bool vis[M];
 16     struct node {
 17         int to,dis,nxt;
 18     } edge[30303<<6];
 19     void add(int from,int to,int dis) {
 20         edge[++cnt].to=to,edge[cnt].dis=dis,edge[cnt].nxt=last[from],last[from]=cnt;
 21         //    edge[++cnt].to=from,edge[cnt].dis=dis,edge[cnt].nxt=last[from],last[from]=cnt;
 22     }
 23     void insert(int from,int to,int dis) {
 24         add(from,to,dis),add(to,from,0);
 25     //    cout<<from<<‘ ‘<<to<<‘ ‘<<dis<<endl;
 26     }
 27     void build() {
 28         for(int i=1; i<=n; i++) {
 29             for(int j=i; j<=n; j++) {
 30                 id[i][j]=++ict;
 31             }
 32         }
 33         for(int i=1; i<=n; i++) {
 34             if(vis[a[i]]) continue ;
 35             vis[a[i]]=1,idw[a[i]]=++ict;
 36         }
 37         //    memset(vis,0,sizeof(vis));
 38         S=0,T=ict+n+1;
 39         for(int i=1; i<=n; i++) {
 40             for(int j=i; j<=n; j++) {
 41                 if(mp[i][j]>0) {//1
 42                     insert(S,id[i][j],mp[i][j]);//cout<<‘1‘<<‘ ‘;
 43                 } else if(mp[i][j]<0) {
 44                     insert(id[i][j],T,-mp[i][j]);//cout<<‘1‘<<‘ ‘;
 45                 }
 46                 insert(id[i][j],ict+i,inf);//2
 47                 insert(id[i][j],ict+j,inf);//cout<<‘2‘<<‘ ‘;
 48                 if(i!=j) { //5
 49                     insert(id[i][j],id[i+1][j],inf);
 50                     insert(id[i][j],id[i][j-1],inf);//cout<<‘5‘<<‘ ‘;
 51                 }
 52             }
 53         }
 54         memset(vis,0,sizeof(vis));
 55         for(int i=1; i<=n; i++) {
 56             if(vis[a[i]]) continue ;
 57             vis[a[i]]=1,insert(idw[a[i]],T,m*a[i]*a[i]);//cout<<‘3‘<<‘ ‘;//3
 58         }
 59         for(int i=1; i<=n; i++) {
 60             insert(ict+i,idw[a[i]],inf);//4
 61             insert(ict+i,T,a[i]);//cout<<‘4‘<<‘ ‘;
 62         //    cout<<"Moxing"; 
 63         }
 64         //    cout<<endl;
 65         return ;
 66     }
 67     int d[M*10];
 68     bool bfs() {
 69         memset(d,0,sizeof(d));
 70         queue<int>q;
 71         d[S]=1;
 72         q.push(S);
 73         while(!q.empty()) {
 74             int x=q.front();
 75             q.pop();
 76             for(int i=last[x]; i; i=edge[i].nxt) {
 77                 int y=edge[i].to;
 78                 if(!d[y] && edge[i].dis) {
 79                     d[y]=d[x]+1;
 80                     q.push(y);
 81                     //cout<<y<<‘ ‘;
 82                 }
 83             }
 84         }
 85         //cout<<d[T]<<‘ ‘;
 86         return d[T];
 87     }
 88     int dfs(int x,int lim) {
 89         if(x==T) return lim;
 90         int f=0,tmp;
 91         for(int i=last[x]; i; i=edge[i].nxt) {
 92             int y=edge[i].to;
 93             if(d[y]==d[x]+1&&edge[i].dis&&(tmp=dfs(y,min(lim,edge[i].dis)))) {
 94                 edge[i].dis-=tmp,edge[i^1].dis+=tmp;
 95                 lim-=tmp;
 96                 f+=tmp;
 97                 if(!lim) return f;
 98             }
 99         }
100         d[x]=0;
101         return f;
102     }
103     long long dinic() {
104         long long res=0;
105         //    cout<<dfs(S,inf)<<‘ ‘;
106         while(bfs()) res+=dfs(S,inf);
107         return res;
108     }
109     struct main {
110         main() {
111             scanf("%d%d",&n,&m);
112             for(int i=1; i<=n; i++) {
113                 scanf("%d",&a[i]);
114             }
115             for(int i=1; i<=n; i++) {
116                 for(int j=i; j<=n; j++) {
117                     scanf("%d",&mp[i][j]);
118                     if(mp[i][j]>0) sum+=mp[i][j];
119                 }
120             }
121             build();
122             long long res=dinic();
123             //    printf("%lld\n",res);
124             sum-=res;
125             printf("%lld\n",sum);
126             exit(0);
127         }
128     } UniversalLove;
129 }
130 int main() {
131     Moxing::main();
132 }
View Code

最大权闭合子图
有一个有向图,每一个点都有一个权值(可以为正或负或0),选择一个权值和最大的子图,使得每个点的后继都在子图里面,这个子图就叫最大权闭合子图。
建图:从源点s向每个正权点连一条容量为权值的边,每个负权点向汇点t连一条容量为权值的绝对值的边,有向图原来的边容量全部为无限大

答案为正权值之和-最小割

为什么呢?以下引用自:https://www.cnblogs.com/dilthey/p/7565206.html

这时,可以得到小结论:
①该带边权有向图的关于s-t最小割,是简单割;
  简单割:割集中所有的边,都与s或t相连接。
  显然的,因为不与s,t相连的边,权值都是INF,最小割不可能割在INF的边上;
  这早在文章http://www.cnblogs.com/dilthey/p/7401563.html中就有出现提到过,实际上,这个带边权有向图就是二分图;

②该图中的每一个简单割产生的两个子图,我们记含有点s的是图S,含有点t的是图T,则图S是闭合图;
  闭合图:在一个图中,我们选取一些点构成集合,若集合中任意点连接的任意出弧,所指向的终点也在V中,则这个集合以及所有这些边构成闭合图。
  证明:简单割内不包含边权为INF的边,即不含有连通两个图的边(除了连接在t点上的边之外);
  即,图S中没有边与图T连通,那么,所有的边都只能连接在图S之内,即为闭合图。

③最小割产生的图S和图T,图S为最大权闭合子图;
  最大权闭合子图:在整个图中,有多个子图是满足闭合图的条件的,其中点权值之和最大的,为最大权闭合子图;
  因为割集中所有的边,不是连接在s上,就是连接在t上;
  我们记割集中,所有连接在s上的边的权值和为x1,所有连接在t上的边的权值和为x2,而割集中所有边权值和为X=x1+x2;
  又,记图S中所有点的权值和为W,记其中正权值之和为w1,负权值之和为 - w2,故W = w1 - w2;
  而 W + X = w1 - w2 + x1 + x2,由于x2 = w2
    (因为图S中所有负权值的点,必然连接到t点,而图S必然要与t分割开;故割集中,“连接在t点上的边权值和”就是“图S中所有负权值点的权值之和,取负”)
  因而W + X = w1 + x1;
  而显然的,w1 + x1是整个图中所有正权值之和,记为SUM;
  故W = SUM - X,即 “图S中所有点的权值和” = “整个图中所有正权值之和”  - “割集中所有边权值和”;
  然后,因为SUM为定值,只要我们取最小割,则“图S中所有点的权值和”就是最大的,即此时图S为图S为最大权闭合子图;
 

最后,我们就有了求解这类问题的完整思路:
  ①先记录整个图中,所有正点权值的和;
  ②建立对应流网络,求最大流,最大流在数值上等于最小割,故我们得到了流网络的s-t最小割;
  ③“所有正点权值的和”减去“s-t最小割”,即得最大权闭合子图的权值和。

bzoj4873-最大权闭合子图

原文:https://www.cnblogs.com/Moxingtianxia/p/11370294.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!