博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[六省联考2017]寿司餐厅(最小割)
阅读量:5032 次
发布时间:2019-06-12

本文共 3168 字,大约阅读时间需要 10 分钟。

题意

思路

由得到的权值不重复可以看出这是一道最大权闭合子图问题 (反正我是没看出来),即最小割

可以看出,如果得到了权值\(d_{l,r}\),可以且必须得到权值\(d_{x,y},(l\leq x \leq y\leq r)\),必须要花费\([l,r]\)这一区间的代价,于是可以得到建图方法

将一个区间看做一个点

  1. \(d_{l,r}>0\)\(ans\) \(+=d_{l,r}\)\(S\)向它连边,边权为\(d_{l,r}\),割掉这条边表示不选择这个值,产生\(d_{l,r}\)的代价

  2. \(d_{l,r}\leq 0\),它向\(T\)连边,边权为\(-d_{l,r}\),割掉这条边表示选择这个值,会产生\(-d_{l,r}\)的代价

  3. 每个区间向它包含的小区间连长度为INF的边,和上面连的边一起表示要么选择放弃正的权值,要么选择负的权值;优化:显然边会重复,区间\([l,r]\)只用向\([l+1,r]\)\([l,r-1]\)连边即可

  4. 每个区间向它所包含的所有寿司编号连边,权值为INF,所有的寿司编号向\(T\)连边,权值为\(a[i]\),表示选择了这个区间的正值就得付出\(a[i]\)的代价;优化:也有重复的连边,\([l,r]\)只用向\(l\)\(r\)连边即可

  5. 每个编号\(i\)向其代号\(a[i]\)连权值为INF的边,代号\(a[i]\)\(T\)连权值为\(m*a[i]*a[i]\)的边,原理同上

此时的最小割即为花费的代价,\(ans=ans-dinic()\)

Code

#include
#define N 50005#define INF 100000000using namespace std;int n,m,s,t,dep[N];int a[N];bool vis[N];struct Edge{ int next,to,flow;}edge[N*6];int head[N],cur[N],cnt=1;inline void add_edge(int from,int to,int flow){ edge[++cnt].next=head[from]; edge[cnt].to=to; edge[cnt].flow=flow; head[from]=cnt;}void add(int from,int to,int flow){ add_edge(from,to,flow); add_edge(to,from,0);}template
void read(T &x){ char c;int sign=1; while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48; while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;}int get_id(int i,int j) {return (i-1)*n+j;}bool bfs(){ queue
q; memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); q.push(s); dep[s]=1; while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i;i=edge[i].next) { int v=edge[i].to; if(edge[i].flow<=0||dep[v]) continue; dep[v]=dep[u]+1; q.push(v); if(v==t) return true; } } return false;}int dfs(int rt,int rest){ if(rt==t) return rest; int used=0; for(int i=cur[rt];i&&used
0) { int k=dfs(v,min(edge[i].flow,rest-used)); if(!k) {dep[v]=0;continue;} edge[i].flow-=k; edge[i^1].flow+=k; used+=k; } } return used;}int dinic(){ int ret=0; while(bfs()) ret+=dfs(s,INF); return ret;}int main(){// freopen("sushi.in","r",stdin);// freopen("sushi.out","w",stdout); int ans=0; read(n);read(m); s=0;t=N-1; for(int i=1;i<=n;++i) { read(a[i]); if(!vis[a[i]]) add(n*(n+1)+a[i],t,m*a[i]*a[i]); vis[a[i]]=1; add(n*n+i,n*(n+1)+a[i],INF); add(n*n+i,t,a[i]); } for(int i=1;i<=n;++i) { for(int j=1;j<=n-i+1;++j) { int b; read(b); if(b>=0) { ans+=b; add(s,get_id(i,i+j-1),b); } else add(get_id(i,i+j-1),t,-b); } } for(int i=1;i<=n;++i) { for(int j=i;j<=n;++j) { if(i==j) { add(get_id(i,j),n*n+i,INF); continue; } add(get_id(i,j),get_id(i+1,j),INF); add(get_id(i,j),get_id(i,j-1),INF); add(get_id(i,j),n*n+i,INF); add(get_id(i,j),n*n+j,INF); } } cout<

转载于:https://www.cnblogs.com/Chtholly/p/11557824.html

你可能感兴趣的文章
http://lorempixel.com/ 可以快速产生假图
查看>>
第一次独立上手多线程高并发的项目的心路历程
查看>>
ServiceStack 介绍
查看>>
Centos7下载和安装教程
查看>>
无谓的通宵加班之后的思索
查看>>
S1的小成果:MyKTV系统
查看>>
从setting文件导包
查看>>
编写一个函数isMerge,判断一个字符串str是否可以由其他两个字符串part1和part2“组合”而成...
查看>>
Github 开源:使用控制器操作 WinForm/WPF 控件( Sheng.Winform.Controls.Controller)
查看>>
PMD使用提醒
查看>>
Codeforces 887D Ratings and Reality Shows
查看>>
论文《A Generative Entity-Mention Model for Linking Entities with Knowledge Base》
查看>>
Linux记录-salt分析
查看>>
Android Studio默认快捷键
查看>>
函数式编程与参数
查看>>
SSAS使用MDX生成脱机的多维数据集CUB文件
查看>>
HDU 2191 【多重背包】
查看>>
51nod 1433 0和5【数论/九余定理】
查看>>
【AHOI2013复仇】从一道题来看DFS及其优化的一般步骤和数组分层问题【转】
查看>>
less 分页显示文件内容
查看>>