bzoj4873: [Shoi2017]寿司餐厅(最小割)
2024-09-04 18:04:00
大佬们是怎么一眼看出这是一个最大权闭合子图的……大佬好强->这里
1.把所有区间$(i,j)$看成一个点,如果权值大于0,则从$S$向他连边,容量为权值,否则从它向$T$连边,容量为权值的相反数
2.对于区间$(i,j)$,向所有的寿司$i$到$j$连边,表示选这个区间这些寿司必须选
3.对每一个寿司类型$w[i]$,为他们各自开一个点,向$T$连边,容量为$m*w[i]*w[i]$
4.对每一个寿司向他们所属的类型$w[i]$连边,容量为$inf$,向$T$连边,容量为$w[i]$
5.对于所有区间$(i,j)$,向区间$(i-1,j),(i,j-1)$连边,容量$inf$,表示选了大的必须选小的
然后用总收益减去最小割就行了
//minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
const int N=,M=;
int head[N],Next[M],ver[M],edge[M],tot=;
int dep[N],cur[N],S,T;
queue<int> q;
inline void add(int u,int v,int e){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot,edge[tot]=e;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot,edge[tot]=;
}
bool bfs(){
while(!q.empty()) q.pop();
for(int i=S;i<=T;++i) cur[i]=head[i];
memset(dep,-,sizeof(dep));
q.push(S),dep[S]=;
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(dep[v]<&&edge[i]){
dep[v]=dep[u]+,q.push(v);
if(v==T) return true;
}
}
}
return false;
}
int dfs(int u,int limit){
if(u==T||!limit) return limit;
int flow=,f;
for(int i=cur[u];i;i=cur[u]=Next[i]){
int v=ver[i];
if(dep[v]==dep[u]+&&(f=dfs(v,min(limit,edge[i])))){
flow+=f,limit-=f;
edge[i]-=f,edge[i^]+=f;
if(!limit) break;
}
}
if(!flow) dep[u]=-;
return flow;
}
int dinic(){
int flow=;
while(bfs()) flow+=dfs(S,inf);
return flow;
}
int n,m,a[],mp[][],id[][],cnt=;
int idw[];bool vis[];ll sum=;
void build(){
S=;
for(int i=;i<=n;++i)
for(int j=;j<=n;++j)
id[i][j]=++cnt;
for(int i=;i<=n;++i)
if(!vis[a[i]]) vis[a[i]]=,idw[a[i]]=++cnt;
T=cnt+n+;
memset(vis,,sizeof(vis));
for(int i=;i<=n;++i)
if(!vis[a[i]]) vis[a[i]]=,add(idw[a[i]],T,m*a[i]*a[i]);
for(int i=;i<=n;++i)
add(i+cnt,idw[a[i]],inf),add(i+cnt,T,a[i]);
for(int i=;i<=n;++i)
for(int j=i;j<=n;++j){
if(mp[i][j]>){
sum+=mp[i][j];
add(S,id[i][j],mp[i][j]);
add(id[i][j],i+cnt,inf);
add(id[i][j],j+cnt,inf);
}
else if(mp[i][j]<){
add(id[i][j],T,-mp[i][j]);
add(id[i][j],i+cnt,inf);
add(id[i][j],j+cnt,inf);
}
if(i!=j){
add(id[i][j],id[i+][j],inf);
add(id[i][j],id[i][j-],inf);
}
}
}
int main(){
//freopen("testdata.in","r",stdin);
n=read(),m=read();
for(int i=;i<=n;++i) a[i]=read();
for(int i=;i<=n;++i)
for(int j=i;j<=n;++j)
mp[i][j]=read();
build();
printf("%lld\n",sum-dinic());
return ;
}
最新文章
- [译] 你应该升级 MQTT3.1.1 的6个理由
- Golang学习 - unicode/utf8 包
- php 文件上传类 实例分享
- 关于HttpsURLConnection的连接问题
- C# ICSharpCode.SharpZipLib
- Websocket原理及使用场景[转载]
- freemarker报错之十五
- How Many Processes Should Be Set For The Receiving Transaction Manager (RTM)
- JS中函数常见的表现形式以及立即执行函数
- Kafka设计解析(七)- Kafka Stream
- bootstrap模态框显示时被遮罩层遮住了
- SpringBoot2.0源码分析(一):SpringBoot简单分析
- OnActionExecuting验证用户登录
- PowerBuilder编程新思维3:适配(三层架构与GraphQL)
- 方格填数-2015决赛C语言A组第一题
- Python3 实现(wxpy)用微信自动定时给朋友定时推广
- logback日志分开纪录
- merage语句
- subprocess.Popen() 常用方法
- Java API 操作Zookeeper
热门文章
- POJ 3349 Snowflake Snow Snowflakes (哈希表)
- AngularJS学习笔记(二) 表单验证案例(ng-repeat/filter)
- 关于CString与VARIANT(CComVariant)之间的转化
- python 标准库 —— http(http.cookiejar)
- 洛谷 P1187 3D模型
- 【QT】对Qt项目开发中遇到的问题的总结
- javascript中eval()函数使用方法
- INT 21H 指令说明及使用方法
- 洛谷【P1236】算24点
- 类方法,实例方法,静态方法,@property的应用