版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/84640108
【题目】
原题地址
给定一幅图,求子图的最大权值,权值定义为边权和-点权和。
,边权
【解题思路】
十分经典的最小割建图。
对于每个点
,连
,对于一条边
,连
用所有边权和减去最小割即可。
考虑为什么是对的?实际上就相当于对一条边限制了选择它的两个端点得到边权,或者放弃边权。
【参考代码】
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+10,INF=0x3f3f3f3f;
int n,m,tot,S,T;
int head[N],cur[N],dis[N];
ll ans;
queue<int>q;
int read()
{
int ret=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
return ret;
}
struct Tway{int v,w,nex;}e[N<<3];
void add(int u,int v,int w)
{
e[++tot]=(Tway){v,w,head[u]};head[u]=tot;
e[++tot]=(Tway){u,0,head[v]};head[v]=tot;
}
bool bfs()
{
memcpy(cur,head,sizeof(head));
memset(dis,-1,sizeof(dis));
while(!q.empty()) q.pop();
q.push(S);dis[S]=0;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=head[x];i;i=e[i].nex)
{
int v=e[i].v;
if(!~dis[v] && e[i].w) dis[v]=dis[x]+1,q.push(v);
}
}
return ~dis[T];
}
int dfs(int x,int flow)
{
if(x==T || !flow) return flow;
int f,used=0;
for(int &i=cur[x];i;i=e[i].nex)
{
int v=e[i].v;
if(dis[v]!=dis[x]+1 || !(f=dfs(v,min(flow-used,e[i].w)))) continue;
e[i].w-=f;e[i^1].w+=f;used+=f;
if(used==flow) break;
}
return used;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("CF1082G.in","r",stdin);
freopen("CF1082G.out","w",stdout);
#endif
n=read();m=read();S=0;T=n+m+1;tot=1;
for(int i=1;i<=n;++i) add(S,i,read());
for(int i=1;i<=m;++i)
{
int u=read(),v=read(),w=read();
add(u,i+n,INF);add(v,i+n,INF);add(i+n,T,w);
ans+=w;
}
while(bfs()) ans-=dfs(S,INF);
printf("%lld\n",ans);
return 0;
}
【总结】
水过了一天。