题意:现在有n个任务,两个机器A和B,每个任务要么在A上完成,要么在B上完成,而且知道每个任务在A和B机器上完成所需要的费用。然后再给m行,每行a,b,w三个数字。表示如果a任务和b任务不在同一个机器上工作的话,需要额外花费w。现在要求出完成所有任务最小的花费是多少。
1:每个任务看成一个顶点,就只有n+2的顶点,然后源点连接到每个任务顶点一条边,权值为这个任务在A机器上所要的花费,每个任务顶点连接到汇点一条边,权值为这个任务在B机器上所要的花费。一开始以A和B机器做为顶点,结果也是正确的,但这样顶点就是2*n+2个,TLE了。
思路: 如果将两个机器分别视为源点和汇点、任务视为顶点,则可以按照以下方式构图:对于第i 个任务在每个机器中的耗费Ai和Bi, 从源点向顶点i连接一条容量为Ai的弧、从顶点i向汇点 连接一条容量为Bi的弧;对于a任务与b任务在不同机器中运行造成的额外耗费w,顶点a 与顶点b连接一条容量为w的弧(双向边,因为消耗是对双方而言)。此时每个顶点(任务)都和源点及汇点(两个机器)相连,即 每个任务都可以在任意一个机器中运行 不难了解到,对于图中的任意一个割,源点与汇点必不连通。因此每个顶点(模块)都不可 能同时和源点及汇点(两个机器)相连,即每个模块只在同一个机器中运行。此时耗费即为割 的容量。很显然,当割的容量取得最小值时,总耗费最小。故题目转化为求最小割的容量。
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=22222;
const int M=1000000;
const int inf=1<<30 ;
struct node
{
int u,v,c,next;
}edge[M];
int head[N],pre[N],dis[N],cur[N],gap[N];
int top ;
void add(int u ,int v,int c)
{
edge[top].u=u;
edge[top].v=v;
edge[top].c=c;
edge[top].next=head[u];
head[u]=top++;
edge[top].u=v;
edge[top].v=u;
edge[top].c=0;
edge[top].next=head[v];
head[v]=top++;
}
int sap(int s,int t ,int nv)
{
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
int u,v,minflow=inf,flow=0;
for(int i = 0 ; i <nv ; i++) cur[i]=head[i] ;
u=pre[s]=s;
gap[s]=nv;
while(dis[s] < nv )
{
loop :
for(int &j=cur[u] ; j!=-1 ; j=edge[j].next)
{
v=edge[j].v ;
if(edge[j].c > 0 && dis[u] == dis[v] +1 )
{
minflow = min(minflow ,edge[j].c) ;
pre[v]=u;
u=v ;
if(v==t)
{
for( u =pre[v] ; v!=s ;v=u,u=pre[u])
{
edge[cur[u]].c -= minflow ;
edge[cur[u]^1].c += minflow ;
}
flow += minflow ;
minflow = inf ;
}
goto loop ;
}
}
int mindis=nv ;
for(int i = head[u] ; i!=-1 ; i=edge[i].next)
{
v=edge[i].v ;
if(edge[i].c > 0 && dis[v] < mindis)
{
mindis = dis[v] ;
cur[u]=i ;
}
}
if(--gap[dis[u]]==0) break ;
gap[ dis[u] = mindis +1 ]++ ;
u=pre[u] ;
}
return flow ;
}
int main()
{
int n,m,x,y,a,b,w;
while(~scanf("%d%d",&n,&m))
{
top= 0;
memset(head,-1,sizeof(head));
int s=0,t=n+1 ;
for(int i = 1 ; i <= n ; i++)
{
scanf("%d%d",&x,&y);
add(s,i,x);
add(i,t,y);
}
for(int i = 1 ; i <= m ; i++)
{
scanf("%d%d%d",&a,&b,&w);
add(a,b,w);
add(b,a,w);
}
int ans=sap(s,t,t+1);
printf("%d\n",ans);
}
return 0;
}