1. 程式人生 > >[六省聯考] 壽司餐廳

[六省聯考] 壽司餐廳

題目描述:

太長了,不描述!

題目分析:

看題面看了10min才反應過來這是個最大權值閉合子圖的問題
應用網路流最小割的模型來解決本問題
首先,每個壽司編號即為器材,代價為 w[i]*w[i]*m
那麼我們由每個壽司編號向匯點連結一條容量為w[i]*w[i]*m
每個壽司一定需要一個壽司編號,代價為 -w[i]
那麼我們由壽司向壽司編號連一條inf的邊,由壽司向匯點連一條容量為w[i]的邊
把每個區間附加值看做一個實驗 然後建邊
注意區間有包含關係!
總結一下:
1.對於所有的(i,j)(i,j)(i,j) 區間收益,將它們各自看做一個點,若權值mpmpmp 為正,從源點連過來,容量為mpmpmp ,若權值為負,連到匯點去,容量為−mp-mp−mp

2.對於所有的(i,j)(i,j)(i,j) 區間收益,向區間內包括的i到j號壽司連邊,容量為INFINFINF ,表示必須選對應的壽司才能選這個區間

3.對於所有的壽司型別w[i]w[i]w[i],為它們各自開一個點,向匯點T連邊,容量為m∗w[i]∗w[i]m*w[i]*w[i]m∗w[i]∗w[i]

4.對於1~n每一個壽司,向它們所屬的型別w[i]w[i]w[i] 連邊,容量為INFINFINF ;向T連邊,容量為C[i]C[i]C[i]

5.對於所有的(i,j)(i,j)(i,j) 區間,向(i+1,j)(i+1,j)(i+1,j) 和(i,j−1)(i,j-1)(i,j−1) 連邊,容量為INF,表示選了大區間肯定得選被大區間包含的小區間

題目連結:

Ac 程式碼:

// luogu-judger-enable-o2
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring> 
#define il inline
using namespace std;
const int inf=0x7fffffff;
const int maxm=110000;
int head[maxm],to[maxm*2],cap[maxm*2],net[maxm*2],deep[maxm],cnt=1;
il void
add(int x,int y,int c){cnt++,to[cnt]=y,cap[cnt]=c,net[cnt]=head[x],head[x]=cnt;} queue <int> dl; int id1[200][200],id2[200],w[1010],cost[200][200]; int n,m; bool vis[maxm]; il bool BFS(int s,int t) { while(!dl.empty()) dl.pop(); memset(deep,-1,sizeof(deep)); dl.push(s),deep[s]=0; while(!dl.empty()) { int x=dl.front();dl.pop(); for(int i=head[x];i;i=net[i]) if(cap[i]>0&&deep[to[i]]==-1) dl.push(to[i]),deep[to[i]]=deep[x]+1; } return deep[t]==-1?0:1; } int dfs(int now,int flow,int t) { if(now==t) return flow; int w,used=0; for(int i=head[now];i;i=net[i]) { int v=to[i]; if(deep[v]==deep[now]+1&&cap[i]) { w=dfs(v,min(flow-used,cap[i]),t); cap[i]-=w; cap[i^1]+=w; used+=w; if(used==flow) return flow; } } if(!used) deep[now]=-1; return used; } il int dinic(int s,int t) { int maxflow=0; while(BFS(s,t)) maxflow+=dfs(s,inf,t); return maxflow; } inline void adx(int x,int y,int cax) { add(x,y,cax),add(y,x,0); } int main() { scanf("%d%d",&n,&m); int tot=0,sum=0; for(int i=1;i<=n;i++) { scanf("%d",&w[i]); if(!vis[w[i]]) id2[w[i]]=++tot; } for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) scanf("%d",&cost[i][j]),id1[i][j]=++tot; int s=0,t=tot+n+10; memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++) if(!vis[w[i]]) adx(id2[w[i]],t,w[i]*w[i]*m),vis[w[i]]=1; for(int i=1;i<=n;i++) adx(tot+i,id2[w[i]],inf),adx(tot+i,t,w[i]); for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) { adx(id1[i][j],tot+i,inf),adx(id1[i][j],tot+j,inf); if(cost[i][j]>0) sum+=cost[i][j],adx(s,id1[i][j],cost[i][j]); else adx(id1[i][j],t,-cost[i][j]); if(i!=j) adx(id1[i][j],id1[i+1][j],inf),adx(id1[i][j],id1[i][j-1],inf); } printf("%d\n",sum-dinic(s,t)); return 0; }