标签:最小 long max stdout main return void 最大 完全
给出一个无向图,可以删掉若干点,删i的代价是ai,最大化Σ|剩余连通块bi之和|-代价
n,m<=300
看错题后的版本:每删掉一个点对其相连连通块计算贡献,使最后和最大
完全不可做
先删掉一些点,对剩下的一个块里的贡献同为+1或-1,则可以转化为对每个点赋+1/-1/删掉,最终贡献为bi*点权之和,且有边相连的点的权相同
先加上Σ|bi|,接下来用最小割使其合法
连S->i1->i2->T,对应+1/删/-1,若bi>=0则为0/bi+ai/2bi,<0则为2|bi|/|bi|+ai/0
如果一个点被删掉了,那么其他点和其的限制会消失,所以对于(u,v)直接连v2->u1和u2->v1的inf边即可
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define abs(x) ((x)>0?(x):-(x))
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define inf 100000000
#define ll long long
//#define file
using namespace std;
int a[100001][3],ls[701],cur[701],A[301],B[301],f[701],g[701],n,m,i,j,k,l,len,ans,st,ed;
void NEW(int x,int y,int z) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;a[len][2]=z;}
void New(int x,int y,int z) {NEW(x,y,z),NEW(y,x,0);}
int dfs(int t,int flow)
{
int i,use=0,w;
if (t==ed) return flow;
for (i=cur[t]; i; i=a[i][1])
{
cur[t]=i;
if (a[i][2] && f[t]==f[a[i][0]]+1)
{
w=dfs(a[i][0],min(a[i][2],flow-use)),use+=w;
a[i][2]-=w,a[i^1][2]+=w;
if (use==flow) return use;
}
}
cur[t]=ls[t];
--g[f[t]];
if (!g[f[t]]) {f[st]=ed+1;return use;}
++f[t],++g[f[t]];
return use;
}
int main()
{
#ifdef file
freopen("f.in","r",stdin);
#endif
scanf("%d%d",&n,&m),len=1;st=n*2+1,ed=n*2+2;
fo(i,1,n) scanf("%d",&A[i]);
fo(i,1,n) scanf("%d",&B[i]),ans+=abs(B[i]);
fo(i,1,n)
if (B[i]>=0)
New(st,i*2-1,0),New(i*2-1,i*2,abs(B[i])+A[i]),New(i*2,ed,2*abs(B[i]));
else
New(st,i*2-1,2*abs(B[i])),New(i*2-1,i*2,abs(B[i])+A[i]),New(i*2,ed,0);
fo(i,1,m) scanf("%d%d",&j,&k),New(j*2,k*2-1,inf),New(k*2,j*2-1,inf);
g[0]=ed;
while (f[st]<=ed) ans-=dfs(st,inf);
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
标签:最小 long max stdout main return void 最大 完全
原文地址:https://www.cnblogs.com/gmh77/p/13908571.html