bzoj4873: [Shoi2017]寿司餐厅(最大权闭合子图)

4873: [Shoi2017]寿司餐厅

大难题啊啊!!!

题目:传送门

题解:一眼题是网络流,但还是不会OTZ,菜啊...

    %题解...

   最大权闭合子图!!!

   好的...开始花式建边:

   1、对于每个区间,我们把它看成一个点,按照权值正负连接源点或汇点(最大权闭合子图的套路)

     2、对于所有的寿司类型k[i],各自开一个点,向ed连边,流量为m*k[i]*k[i];

     3、对于1~n的每个寿司,向它的所属类型连边,流量为无限大;再向ed连边,流量为e[i]。

     4、对于所有的区间i~j,向(i+1,j)和(i,j-1)连边,因为区间具有包含性。

     WA了...再%题解...

     漏了第五种情况:

     5、对于所有区间,向区间内所有的点连边,流量为无限大,表示必须选对应的寿司才能选这个区间QWQ 

       跑网络流。。。

蒟蒻的代码(丑的一匹,慎点):

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 #define qread(x)x=read();
  7 using namespace std;
  8 typedef long long LL;
  9 inline int read()
 10 {
 11     int f=1,x=0;char ch;
 12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
 14     return f*x;
 15 }
 16 struct node
 17 {
 18     int x,y,c,next,other;
 19 }a[2110000];int last[1110000],len;
 20 int st,ed,n,m;
 21 void ins(int x,int y,int c)
 22 {
 23     int k1,k2;
 24     len++;k1=len;
 25     a[len].x=x;a[len].y=y;a[len].c=c;
 26     a[len].next=last[x];last[x]=len;
 27     
 28     len++;k2=len;
 29     a[len].x=y;a[len].y=x;a[len].c=0;
 30     a[len].next=last[y];last[y]=len;
 31     
 32     a[k1].other=k2;
 33     a[k2].other=k1;
 34 }
 35 int list[11000],h[11000];
 36 int head,tail;
 37 bool bfs()
 38 {
 39     memset(h,0,sizeof(h));h[st]=1;
 40     list[1]=st;head=1;tail=2;
 41     while(head!=tail)
 42     {
 43         int x=list[head];
 44         for(int k=last[x];k;k=a[k].next)
 45         {
 46             int y=a[k].y;
 47             if(h[y]==0 && a[k].c>0)
 48             {
 49                 h[y]=h[x]+1;
 50                 list[tail++]=y;
 51             }
 52         }
 53         head++;
 54     }
 55     if(h[ed]>0)return true;
 56     return false;
 57 }
 58 int findflow(int x,int flow)
 59 {
 60     if(x==ed)return flow;
 61     int s=0,t;
 62     for(int k=last[x];k;k=a[k].next)
 63     {
 64         int y=a[k].y;
 65         if(h[y]==h[x]+1 && a[k].c>0 && flow>s)
 66         {
 67             t=findflow(y,min(a[k].c,flow-s));
 68             s+=t;
 69             a[k].c-=t;a[a[k].other].c+=t;
 70         }
 71     }
 72     if(s==0)h[x]=0;
 73     return s;
 74 }
 75 int e[110];
 76 int d[110][110];
 77 int id1[110][110],id2[1100];
 78 bool v[1100];
 79 int jb()
 80 {
 81     memset(v,false,sizeof(v));
 82     LL sum=0,cnt=0;
 83     for(int i=1;i<=n;i++)    
 84         for(int j=i;j<=n;j++)
 85             id1[i][j]=++cnt;
 86     
 87     for(int i=1;i<=n;i++)
 88         if(v[e[i]]==0)
 89         {
 90             v[e[i]]=true;
 91             id2[e[i]]=++cnt;
 92         }
 93         
 94     ed=cnt+n+1;
 95     memset(v,false,sizeof(v));
 96     for(int i=1;i<=n;i++)
 97         if(v[e[i]]==0)
 98         {
 99             v[e[i]]=true;
100             ins(id2[e[i]],ed,m*e[i]*e[i]);//种类的花费,和ed连边
101         }
102     for(int i=1;i<=n;i++)
103     {
104         ins(cnt+i,id2[e[i]],999999999);
105         ins(cnt+i,ed,e[i]);
106     }
107     for(int i=1;i<=n;i++)
108         for(int j=i;j<=n;j++)
109         {
110             if(d[i][j]>0)
111             {
112                 sum+=d[i][j];
113                 ins(st,id1[i][j],d[i][j]);
114                 ins(id1[i][j],cnt+i,999999999);
115                 ins(id1[i][j],cnt+j,999999999);
116             }
117             else if(d[i][j]<0)
118             { 
119                 ins(id1[i][j],ed,-d[i][j]);
120                 ins(id1[i][j],cnt+i,999999999);
121                 ins(id1[i][j],cnt+j,999999999);
122             }
123             if(i!=j)
124             {
125                 ins(id1[i][j],id1[i][j-1],999999999);
126                 ins(id1[i][j],id1[i+1][j],999999999);
127             }
128         }
129     return sum;
130 }
131 int main()
132 {
133     qread(n);qread(m);
134     for(int i=1;i<=n;i++)qread(e[i]);
135     for(int i=1;i<=n;i++)
136         for(int j=i;j<=n;j++)
137             qread(d[i][j]);
138     st=0;
139     LL sum=jb();
140     /*
141     for(int i=1;i<=len;i++)
142             if(a[i].x==0)
143                 printf("%d %d
",a[i].y,a[i].c);
144     printf("
");
145     for(int i=1;i<=len;i++)
146             if(a[i].y==ed)
147                 printf("%d %d
",a[i].x,a[i].c);
148     */
149     int ans=0;
150     while(bfs())ans+=findflow(st,999999999);
151     printf("%lld
",sum-ans);
152     return 0;
153 }
原文地址:https://www.cnblogs.com/CHerish_OI/p/8010634.html