题面太长,请诸位自行品尝—>寿司餐厅
分析:
首先题目中给了限制条件,假如选了D(i,j)(i<j),那么也就选了D(i+1,j)和D(i,j-1)两个点。
于是我们一下就明白了,哦,最大权闭合子图~
所以我们让每一个D代表一个点,然后对于每个D(i,j)代表的点,分别向D(i+1,j)和D(i,j-1)所代表的点连边(容量为inf),然后按照最大权闭合子图的建图方式建图~
完了?
并没有。我们接着看题面,其实代价还有一个,是mx^2+cx,这个我们怎么加上?
直接看啥也看不出来,所以我们拆开来看。首先,mx^2是由代号和常数m决定的,所以我们可以把它独立开来,对每个编号建立一个点,因为它是代价,所以点权是负的,所以我们从它向汇点T连一条边权为mx^2的边,然后把每个代号为x的寿司向它代号那个点连边。
再考虑cx怎么计算,这个好办,多选一种编号为x的寿司就会产生x的代价,所以我们把每种寿司向T点连边,容量为x即可产生费用。
代码:
1 #include<bits/stdc++.h> 2 #define ms(a,x) memset(a,x,sizeof(a)) 3 #define p(x,y) ((x-1)*n+y+1000) 4 using namespace std;int S,T,tot; 5 const int N=40000,inf=0x3f3f3f3f; 6 struct node{int y,z,nxt;}e[N*64];int a[N]; 7 int c=1,h[N],d[N],m,k,n,ans,q[N],sn[N],g,sm; 8 void add(int x,int y,int z){ 9 e[++c]=(node){y,z,h[x]};h[x]=c; 10 e[++c]=(node){x,0,h[y]};h[y]=c; 11 } bool bfs(){int f=1,t=0;ms(d,-1); 12 d[S]=0;q[++t]=S; 13 while(f<=t){ 14 int x=q[f++]; 15 for(int i=h[x],y;i;i=e[i].nxt) 16 if(d[y=e[i].y]==-1&&e[i].z) 17 d[y]=d[x]+1,q[++t]=y; 18 } return (d[T]!=-1); 19 } int dfs(int x,int f){ 20 if(x==T) return f;int w,tmp=0; 21 for(int i=h[x],y;i;i=e[i].nxt) 22 if(d[y=e[i].y]==d[x]+1&&e[i].z){ 23 w=dfs(y,min(e[i].z,f-tmp)); 24 if(!w) d[y]=-1;e[i].z-=w; 25 e[i^1].z+=w;tmp+=w;if(tmp==f) return f; 26 } return tmp; 27 } void solve(){ 28 while(bfs()) tot+=dfs(S,inf); 29 } int main(){ 30 scanf("%d%d",&n,&m);S=0;T=n*n+1001; 31 for(int i=1;i<=n;i++){ 32 scanf("%d",&a[i]); 33 if(m&&!sn[a[i]]) 34 sn[a[i]]=1,add(a[i],T,a[i]*a[i]); 35 add(p(i,i),a[i],inf); 36 add(p(i,i),T,a[i]); 37 } for(int i=1;i<=n;i++) 38 for(int j=i;j<=n;j++){ 39 scanf("%d",&g);sm+=(g>0?g:0); 40 if(g>0) add(S,p(i,j),g); 41 else add(p(i,j),T,-g); 42 if(i!=j) add(p(i,j),p(i+1,j),inf); 43 if(i!=j) add(p(i,j),p(i,j-1),inf); 44 } solve();printf("%d ",sm-tot);return 0; 45 }