题解:P9153 「SvR-2」1+2=3(加强版)
友情提示:本题解 看起来错误,但 本蒟蒻 认为是正确的,如有不严谨欢迎各位大佬多多指出。
题意
题目说有
现在要把它们 从左到右 拼起来,求问最多有多少对相邻的木棍使得连接他们的两个数的和为
题解
看上去没有头绪,感觉像有源汇上下界最大费用最大流套路 而且数据范围很大,所以我们考虑 正难则反。
我们把木棍抽象成边,数抽象成点,绘制一张图。(这里就不放了)
然后我们发现这张图不太好用,因为我们没法表示和为
下图为更改后的图:
那么我们会发现,这张图上每拿掉一条长度为
那么显然我们取完路径之后,
我们设
这是对的吗?不对!有特殊情况。假设某个连通块内没有废边,但是一条路径一定有起点,这时答案仍要减
然后(就没有然后了)……
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define N 1010
int fa[N],r[N],c[N];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
signed main(){
int t; cin>>t;
while (t--){
memset(r,0,sizeof(r));
memset(c,0,sizeof(c));
int n,ans=0; cin>>n;
for (int i=0; i<=n; i++) fa[i]=i;
for (int i=0; i<n; i++){
for (int j=0; j<n; j++){
int x; cin>>x;
if (x){
ans+=x; r[i]+=x; c[n-j]+=x;
if (find(i)!=find(n-j)){
fa[find(i)]=find(n-j);
}
}
}
}
for (int i=0; i<=n; i++){
if (find(i)!=i||!c[i]&&!r[i]) continue;//小心空连通块
int sum=0,flag=0;
for (int j=0; j<=n; j++) if (find(j)==i) sum+=abs(r[j]-c[j]);
ans-=max(sum>>1,1ll);
}
cout<<ans<<"\n";
}
}