POJ 3469 Dual Core CPU | 最小割
题面:
有两个集合,现在又n个点,第i个点在A集合花费Ai代价,在B集合花费Bi代价
然后又m个限制,每个限制是a,b,c,说a和b如果不在一个集合就会多花费c代价。
现在要让每个点属于一个集合,求最小代价
题解:
相当于把n个点划分为两个集合,我们设A为源点S,B为汇点T,对于每个点向S和T连权值大小的边
对于每个限制a,b,c,建双向边让a连b,b连a,大小都为c,求出图中的最小割,就是把n个点,划分为两个集合的最小代价
又因为最小割==最大流,跑DINIC即可了.
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 20010
#define M 800010
#define INF 100000000
using namespace std;
int head[N],cur[N],lev[N],ecnt=1,S,T,n,m;
queue <int> q;
struct adj
{
int nxt,v,w;
}e[2*M];
void add(int u,int v,int w)
{
e[++ecnt].v=v,e[ecnt].w=w,e[ecnt].nxt=head[u],head[u]=ecnt;
e[++ecnt].v=u,e[ecnt].w=0,e[ecnt].nxt=head[v],head[v]=ecnt;
}
inline int bfs()
{
int u,v;
for (int i=S;i<=T;i++)
lev[i]=-1,cur[i]=head[i];
q.push(S),lev[S]=0;
while (!q.empty())
{
u=q.front();
for (int i=head[u];i;i=e[i].nxt)
{
if (e[i].w>0 && lev[v=e[i].v]==-1)
lev[v]=lev[u]+1,q.push(v);
}
q.pop();
}
return lev[T]!=-1;
}
inline int Dinic(const int &u,const int &flow)
{
if (u==T) return flow;
int res=0,v,delta;
for (int &i=cur[u];i;i=e[i].nxt)
{
if (e[i].w>0 && lev[u]<lev[v=e[i].v])
{
delta=Dinic(v,min(e[i].w,flow-res));
if (delta)
{
e[i].w-=delta;e[i^1].w+=delta;
res+=delta;if (res==flow) break;
}
}
}
if (res!=flow) lev[u]=-1;
return res;
}
inline int Maxflow()
{
int ans=0;
while (bfs()) ans+=Dinic(S,INF);
return ans;
}
inline void init()
{
memset(head,0,sizeof(head));
ecnt=1;
}
int main()
{
scanf("%d%d",&n,&m);
S=0,T=n+1;
for (int i=1,a,b;i<=n;i++)
scanf("%d%d",&a,&b),add(S,i,a),add(i,T,b);
for (int i=1,u,v,w;i<=m;i++)
scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
printf("%d",Maxflow());
return 0;
}

浙公网安备 33010602011771号