您的位置:首页 > 其它

【JZOJ5307】【NOIP2017提高A组模拟8.18】偷窃

2017-08-23 22:04 369 查看

Description



Data Constraint



Solution

在考场上理解错题意,竟然还有85分!!!上帝保佑

真正的题意是可以移动一个金砖到另一堆上。

我们考虑求每一行每一列的最大值,若有一行一列满足最大值相同且交点的金砖数量不为空的话,那么显然是可以通过然交点为该值从而同时满足行与列的要求。因此我们先将所有行与列的最大值相加,若有一行一列满足最大值相同且交点的金砖数量不为空的话,那么该行向该列连一条边。最后跑一下二分图即可。所有点总和减去(和减去最大匹配)即为答案。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=3e4+5,mo=1e15+5;
ll a[200][200],h[maxn],l[maxn],first[maxn],last[maxn],next[maxn],value[maxn],dui[maxn];
ll n,m,i,t,j,k,x,y,z,ans,s,sum,v[maxn],d[maxn],num;
void lian(ll x,ll y,ll z){
last[++num]=y;next[num]=first[x];first[x]=num;value[num]=z;
}
ll bfs(){
int i=0,j=1;memset(d,0,sizeof(d));d[0]=1;
while (i<j){
x=v[++i];
for (t=first[x];t;t=next[t]){
if (d[last[t]] ||!value[t]) continue;
d[v[++j]=last[t]]=d[x]+1;
}
}
return d[s];
}
ll dg(ll x,ll sum){
ll t,p=sum,k;
if (x==s) return sum;
for (t=first[x];t;t=next[t]){
if (!value[t]||d[last[t]]!=d[x]+1) continue;
k=dg(last[t],min(value[t],p));
if (k){
value[t]-=k;value[dui[t]]+=k;p-=k;
if (!p)break;
}
}
if (p==sum) d[x]=-1;
return sum-p;
}
int main(){
//  freopen("data.in","r",stdin);
scanf("%lld%lld",&n,&m);s=n+m+1;
for (i=1;i<=n;i++)
for (j=1;j<=m;j++){
scanf("%lld",&a[i][j]);a[i][j]-=(a[i][j]>0);
if (h[i]<a[i][j]) h[i]=a[i][j];
if (l[j]<a[i][j]) l[j]=a[i][j];
ans+=a[i][j];
}
for (i=1;i<=n;i++)
for (j=1;j<=m;j++)
if (h[i]==l[j] && a[i][j]) lian(i,j+n,h[i]),lian(j+n,i,0);
for (i=1;i<=n;i++)lian(0,i,h[i]),lian(i,0,0),sum+=h[i];
for (i=1;i<=m;i++)lian(i+n,s,l[i]),lian(s,i+n,0),sum+=l[i];
for (i=1;i<=num;i++)
if (i%2) dui[i]=i+1,dui[i+1]=i;
while (bfs()) sum-=dg(0,mo);
printf("%lld\n",ans-sum);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: