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;
}

 

posted @ 2017-12-01 14:41  MSPqwq  阅读(131)  评论(0编辑  收藏  举报