Magic Slab

链接:https://ac.nowcoder.com/acm/contest/847/F
来源:牛客网

lililalala得到了一块魔法板,这块魔法板可以被看做大小为\ n \times n n×n的矩形,它含有\ n \times n n×n个单元格。
lililalala可以通过点亮这块魔法板的某些部分获得一定的能量值。
给定两个长度为\ n n的数列\ a a和\ b b以及一个\ n \times n n×n的矩阵\ c c。具体规则如下:
可以花费\ a_{i} a
i

点能量点亮魔法板(从上往下,下同)的第\ i i行\ (1 \le i \le n) (1≤i≤n)。
可以花费\ b_{i} b
i

点能量点亮魔法板(从左往右,下同)的第\ i i列\ (1 \le i \le n) (1≤i≤n)。
如果第\ i i行和第\ j j列同时被点亮,那么就认为第\ i i行的第\ j j个单元格被点亮,可以获得\ c_{ij} c
ij

点能量\ (1 \le i,j \le n) (1≤i,j≤n)。
此外魔法板有额外的关联奖励,每条关联奖励包含两个单元格,也就是说如果如果同时点亮了两个单元格且它们之间有关联奖励,那么就能额外获得一部分能量。
假设lililalala初始有足够多的能量,他想知道采取最优策略后他最多能赚取多少能量?(赚取的能量=获得的能量-消耗的能量)。
输入描述:
第一行两个整数\ n,m(1 \le n \le 40,0 \le m \le 1000) n,m(1≤n≤40,0≤m≤1000)–魔法板的大小和关联奖励的条数。
然后的\ n n行表示矩阵\ c c,\ n n行中的第\ i i行第\ j j个整数表示\ c_{ij} c
ij

(1 \le c_{ij} \le 5000)(1≤c
ij

≤5000)–点亮第\ i i行的第\ j j个单元格可以获得的能量。
然后的一行\ n n个整数\ a_{1},a_{2},a_{3}…a_{n} ( \ 1 \leq \ a_{1},a_{2},a_{3}…a_{n} \leq 5000 ) a
1

点能量。
输出描述:
输出一行包含一个整数–lililalala最多能赚取的能量。
示例1
输入
复制
2 0
3 1
1 5
2 2
2 2
输出
复制
2
示例2
输入
复制
3 1
12 3 7
4 8 1
1 2 8
2 9 7
3 15 4
3 1 3 3 8
输出
复制
20


明显的最大权闭合子图,对于收益和花费建图最小割即可。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1e4+10,M=1e6+10;
int n,m,s,t,base,x,res,h[N];
int head[N],nex[M],to[M],w[M],tot=1;
inline void ade(int a,int b,int c){
	to[++tot]=b; nex[tot]=head[a]; w[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c){
	ade(a,b,c);	ade(b,a,0);
}
inline int id(int x,int y){
	return (x-1)*n+y;
}
inline int bfs(){
	memset(h,0,sizeof h);	h[s]=1;	queue<int> q;	q.push(s);
	while(q.size()){
		int u=q.front();	q.pop();
		for(int i=head[u];i;i=nex[i]){
			if(w[i]&&!h[to[i]]){
				h[to[i]]=h[u]+1;	q.push(to[i]);
			}
		}
	}
	return h[t];
}
int dfs(int x,int f){
	if(x==t)	return f;
	int fl=0;
	for(int i=head[x];i&&f;i=nex[i]){
		if(w[i]&&h[to[i]]==h[x]+1){
			int mi=dfs(to[i],min(w[i],f));
			w[i]-=mi; w[i^1]+=mi; fl+=mi; f-=mi;
		}
	}
	if(!fl)	h[x]=-1;
	return fl;
}
int dinic(){
	int res=0;
	while(bfs())	res+=dfs(s,inf);
	return res;
}
signed main(){
	cin>>n>>m;	base=n*n;	t=base+2*n+m+10;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>x;	add(s,id(i,j),x);	res+=x;
			add(id(i,j),base+j,inf);	add(id(i,j),base+n+i,inf);
		}
	}
	for(int i=1;i<=n;i++)	cin>>x,add(base+n+i,t,x);
	for(int i=1;i<=n;i++)	cin>>x,add(base+i,t,x);
	for(int i=1;i<=m;i++){
		int x1,y1,x2,y2,k;	cin>>x1>>y1>>x2>>y2>>k;	res+=k;	int d=i+base+2*n;
		add(s,d,k); add(d,base+n+x1,inf); add(d,base+n+x2,inf);
		add(d,base+y1,inf);	add(d,base+y2,inf);
	}
	cout<<res-dinic()<<endl;
	return 0;
}
全部评论

相关推荐

11-30 11:07
河南大学 Java
宇宙厂 测开 n*15
丘丘给个offer:有后选后
点赞 评论 收藏
分享
11-04 14:10
东南大学 Java
_可乐多加冰_:去市公司包卖卡的
点赞 评论 收藏
分享
一颗宏心:华为HR晚上过了十二点后还给我法消息。
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务