bzoj1497[NOI2006]最大获利

添加超级源和超级汇,然后将s和正权边相连,负权边和t相连,这时候对应的每一个割对应着一种方案,然后最小割即可

胡伯涛《最小割模型在信息学竞赛中的应用》

论文如上orzzzzzz,不过他提出来的超级神的40s变成0.71s的优化会慢成原来的两倍23333333333333333
还有就是千万不能先把ne=0,然后在得到反边的时候直接+1,会挂的orzzzzzz然而不强制奇数直接+1为什么会错呢还没想明白
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define LL long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,x) for(int i=last[x];i!=0;i=e[i].next)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 6005
#define M 50005
#define inf 0x7fffffff
struct edge
{
	int y,f,next;
}e[M*10];
int last[N*10],ne=1;
int h[N*10];
int n,m;

void add(int x,int y,int w)
{
	e[++ne].y=y;e[ne].f=w;e[ne].next=last[x];last[x]=ne;
}

void add2(int u,int v,int w)
{
	add(u,v,w);add(v,u,0);
}

int q[N*10];
bool bfs(int s,int t)
{
	memset(h,0,sizeof(h));
	int head=0,tt=1;
	q[1]=s;h[s]=1;
	while(head<tt)
	{
		int now=q[++head];
		if(now==t)return 1;
		efo(i,now)
		if(h[e[i].y]==0&&e[i].f)
		{
//			cout<<e[i].y<<' '<<e[i].f<<endl;
			q[++tt]=e[i].y;
			h[e[i].y]=h[now]+1;
		}
	}
	return 0;
}

int dfs(int x,int maxf,int t)
{
//	cout<<x<<' '<<maxf<<' '<<t<<endl;
	if(x==t) return maxf;
	int ret=0,f=0;
	efo(i,x)
	if(e[i].f!=0&&h[e[i].y]==h[x]+1)
	{
		f=dfs(e[i].y,min(maxf-ret,e[i].f),t);
//		cout<<e[i].y<<' '<<f<<endl;
		e[i].f-=f;
		e[i^1].f+=f;
		ret+=f;
		if(ret==maxf)return ret;
	}
	return ret;
}

int dinic(int s,int t)
{
	int ans=0;
//	cout<<"begin"<<endl;
	while(bfs(s,t))ans+=dfs(s,inf,t);
	return ans;
}

int main()
{
	n=read(),m=read();
	fo(i,1,n)
	{
		int x=read();
		add2(0,i,x);
	}
	int sum=0;
	fo(i,1,m)
	{
		int x=read(),y=read(),w=read();
		add2(x,n+i,inf);
		add2(y,n+i,inf);
		add2(n+i,n+m+1,w);
		sum+=w;
	}
	int ans=dinic(0,n+m+1);
	cout<<sum-ans<<endl;
	return 0;
}


你可能感兴趣的:(网络流)