想看更多的解题报告:http://blog.csdn.net/wangjian8006/article/details/7870410
转载请注明出处:http://blog.csdn.net/wangjian8006
题目大意:有两个CPU,现在又n个任务,任务在第A个CPU里面执行所花费Ai代价,在第B个CPU里面执行所花费Bi代价
然后又m个限制,每个限制是a,b,c,说任务a和任务b如果不在一个CPU执行就会多花费c代价。
解题思路:基本上看分成2部分就可以直觉感觉是求最小割,割值就是在平面画一条直线,将所有点分为两部分,然后算图上和这条直线相交的边的权值和。而对于最小割来说,最大流流量就是最小割的容量。
而划分方法,就是将最大流后残余网络中s可以走到的点划为s集合,其余点划为t集合,注意,不是可以走到t的点,因为有可能有一条线上的多条边都流满的情况,这种情况下有些点就无法走到t,而且s也走不到它。
这样建图:一个超级源点指向所有任务,容量为任务点在A上所花的代价,反向边容量为0
然后所有任务点指向一个超级汇点,容量为任务点在B上所花的代价,反向边容量为0
然后多花费代价c,就让a和b之间连一条边,来回的容量都为c
/*
dinic+邻接表
Memory 9952K
Time 4844MS
*/
#include <iostream>
#include <queue>
using namespace std;
#define INF INT_MAX
#define MAXE 500000
#define MAXV 20100
#define min(a,b) (a>b?b:a)
typedef struct{
int s,t,r,contrary,next;
}Edge;
Edge edge[MAXE];
int n,m,source,sink,edge_sum,maxflow;
int head[MAXV],dis[MAXV];
void addedge(int x,int y,int c,int flag){
edge[edge_sum].s=x;
edge[edge_sum].t=y;
edge[edge_sum].r=c;
edge[edge_sum].contrary=edge_sum+1;
edge[edge_sum].next=head[x];
head[x]=edge_sum++;
edge[edge_sum].s=y;
edge[edge_sum].t=x;
edge[edge_sum].contrary=edge_sum-1;
edge[edge_sum].r=(flag?c:0);
edge[edge_sum].next=head[y];
head[y]=edge_sum++;
}
int bfs(){
int i,v,tmp;
queue <int>q;
memset(dis,0,sizeof(dis));
dis[source]=1;
q.push(source);
while(!q.empty()){
v=q.front();q.pop();
for(i=head[v];i!=-1;i=edge[i].next){
tmp=edge[i].t;
if(!dis[tmp] && edge[i].r){
dis[tmp]=dis[v]+1;
if(tmp==sink) return 1;
q.push(tmp);
}
}
}
return 0;
}
int dfs(int cur,int cp){
if(cur==sink) return cp;
int tmp=0,i,a,t;
for(i=head[cur];i!=-1 && tmp<cp;i=edge[i].next){
a=edge[i].t;
if(dis[a]==dis[cur]+1 && edge[i].r){
t=dfs(a,min(edge[i].r,cp-tmp));
edge[i].r-=t;
edge[edge[i].contrary].r+=t;
tmp+=t;
}
}
if (!tmp) dis[cur]=-1; //这里代表流已经没了,或者说此路不通
return tmp;
}
void dinic(){
maxflow=0;
while(bfs()) maxflow+=dfs(source,INF);
}
int main(){
int i,a,b,c;
while(~scanf("%d%d",&n,&m)){
source=0;sink=n+1,edge_sum=0;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
scanf("%d%d",&a,&b);
addedge(source,i,a,0); //这是连的有向边
addedge(i,sink,b,0);
}
for(i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c,1); //这里连无向边
}
dinic();
printf("%d\n",maxflow);
}
return 0;
}
==========================================================================================================
/*
sap+gap+邻接表
Memory 8080K
Time 2375MS
*/
#include <iostream>
using namespace std;
#define INF INT_MAX
#define MAXE 500000
#define MAXV 20100
#define min(a,b) (a>b?b:a)
typedef struct{
int t,r,contrary,next;
}Edge;
Edge edge[MAXE];
int n,m,source,sink,edge_sum,maxflow;
int head[MAXV],dis[MAXV],cur[MAXV],gap[MAXV],pre[MAXV];
void addedge(int x,int y,int c,int flag){
edge[edge_sum].t=y;
edge[edge_sum].r=c;
edge[edge_sum].next=head[x];
head[x]=edge_sum++;
edge[edge_sum].t=x;
edge[edge_sum].r=(flag?c:0);
edge[edge_sum].next=head[y];
head[y]=edge_sum++;
}
void sap(){
int u=pre[source]=source,tmp=INF,v,a;
memset(dis,0,sizeof(dis));
memset(gap,0,sizeof(gap));
for(v=0;v<=n;v++) cur[v]=head[v];
gap[source]=n;
maxflow=0;
while(dis[source]<n){
loop:
for(v=cur[u];v!=-1;v=edge[v].next){
a=edge[v].t;
if(dis[u]==dis[a]+1 && edge[v].r>0){
cur[u]=v;
tmp=min(tmp,edge[v].r);
pre[a]=u;
u=a;
if(u==sink){
while(u!=source){
u=pre[u];
edge[cur[u]].r-=tmp;
edge[cur[u]^1].r+=tmp;
}
maxflow+=tmp;
tmp=INF;
}
goto loop;
}
}
int mind=n;
for(v=head[u];v!=-1;v=edge[v].next){
a=edge[v].t;
if(edge[v].r>0 && mind>dis[a]){
cur[u]=v;
mind=dis[a];
}
}
if((--gap[dis[u]])==0) break;
gap[dis[u]=mind+1]++;
u=pre[u];
}
}
int main(){
int i,a,b,c;
while(~scanf("%d%d",&n,&m)){
source=0;sink=n+1,edge_sum=0;
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
scanf("%d%d",&a,&b);
addedge(source,i,a,0); //这是连的有向边
addedge(i,sink,b,0);
}
for(i=0;i<m;i++){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b,c,1); //这里连无向边
}
n+=2;
sap();
printf("%d\n",maxflow);
}
return 0;
}