網絡流。
原理:
1、把所有的頂點bfs,根據拓撲序列標記層數。
2、dfs走一遍所有可走的子節點,同時把流量記下來。每次紀錄流量的時候,正向邊加上對應流量,反向邊減去對應邊,
放一下模板
int N,M;
struct pp
{
int v,next,w,re;
}pra[SIZE_M];
int e,head[SIZE_N];
void init()
{
e = 0;
memset(head,-1,sizeof(head[0]) * (N + 10) );
}
void addedge(int x,int y,int z1,int z2)
{
pra[e].re = e+1;
pra[e].v = y;
pra[e].w = z1;
pra[e].next = head[x];
head[x] = e++;
pra[e].re = e-1;
pra[e].v = x;
pra[e].w = z2;
pra[e].next = head[y];
head[y] = e++;
}
int level[SIZE_N];
void bfs(int x)
{
memset(level, -1, sizeof(level[0])* (N + 10));
level[x] = 0;
queue<int> que;
que.push(x);
while (!que.empty()){
int ver = que.front();
que.pop();
for (int i = head[ver]; i != -1; i = pra[i].next){
int u = pra[i].v;
if (pra[i].w > 0 && level[u] < 0){
level[u] = level[ver]+1;
que.push(u);
}
}
}
}
int dfs(int s,int t,int cap)//一次dfs把當前經過的都算了
{
if (s == t) return cap;//若當前頂點就是終點
int addc = 0;
int ver = s;
for (int i = head[ver]; i != -1 && cap - addc > 0; i = pra[i].next){
int u = pra[i].v;
if (pra[i].w > 0 && level[ver] < level[u]){//如果可以增廣而且當前點在父節點的下一層
int f = dfs(u,t,min(cap-addc,pra[i].w));
if (f > 0){
pra[i].w -= f;
addc += f;//一次dfs把當前經過的子節點的最大流都算了
pra[pra[i].re].w += f;
}
}
}
if (!addc) level[s] = -1;//如果當前節點不存在增廣路,那麼其他節點要是指向這條路的話
return addc;
}
int max_flow(int s,int t)
{
int flow = 0;
while (1){
bfs(s);//bfs將當前的頂點按照拓撲序列排列
if (level[t] < 0)
return flow;//如果bfs失敗,說明沒有路了
int temp;
while ( (temp = dfs(s,t,INF)) > 0){
flow += temp;
}
}
}
先放代碼:
</pre><pre name="code" class="cpp">/*題意:有a核和b核,然後有a核的處理時間ai,b核的處理時間bi。
如果某兩個特定任務不在同一個核上進行那麼有附加時間ci;
解答:有一個源點,一個匯點,和其餘的n個點。
源點連向其餘的點,邊權爲ai,其餘的點連向匯點,邊權爲bi。
建圖原因:
首先,如果沒有條件2,那麼肯定是選ab中最小的。單條路徑的最大流就是當前路徑中能經過的最大流量,也就是最細管道的流量
增加了條件2,那麼如果要使用這些增加的ci值的那條路徑, 那麼,肯定序號i和序號j使用的是同個核。設i,j使用a。
*/
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>
#define INF 0x3f3f3f3f
#define SIZE_N 88005
#define SIZE_M 880005//開500005就會RE
using namespace std;
int N,M;
struct pp
{
int v,next,w,re;
}pra[SIZE_M];
int e,head[SIZE_N];
void init()
{
e = 0;
memset(head,-1,sizeof(head[0]) * (N + 10) );
}
void addedge(int x,int y,int z1,int z2)
{
pra[e].re = e+1;
pra[e].v = y;
pra[e].w = z1;
pra[e].next = head[x];
head[x] = e++;
pra[e].re = e-1;
pra[e].v = x;
pra[e].w = z2;
pra[e].next = head[y];
head[y] = e++;
}
int level[SIZE_N];
void bfs(int x)
{
memset(level, -1, sizeof(level[0])* (N + 10));
level[x] = 0;
queue<int> que;
que.push(x);
while (!que.empty()){
int ver = que.front();
que.pop();
for (int i = head[ver]; i != -1; i = pra[i].next){
int u = pra[i].v;
if (pra[i].w > 0 && level[u] < 0){
level[u] = level[ver]+1;
que.push(u);
}
}
}
}
int dfs(int s,int t,int cap)//一次dfs把當前經過的都算了
{
if (s == t) return cap;//若當前頂點就是終點
int addc = 0;
int ver = s;
for (int i = head[ver]; i != -1 && cap - addc > 0; i = pra[i].next){
int u = pra[i].v;
if (pra[i].w > 0 && level[ver] < level[u]){//如果可以增廣而且當前點在父節點的下一層
int f = dfs(u,t,min(cap-addc,pra[i].w));
if (f > 0){
pra[i].w -= f;
addc += f;//一次dfs把當前經過的子節點的最大流都算了
pra[pra[i].re].w += f;
}
}
}
if (!addc) level[s] = -1;//如果當前節點不存在增廣路,那麼其他節點要是指向這條路的話
return addc;
}
int max_flow(int s,int t)
{
int flow = 0;
while (1){
bfs(s);//bfs將當前的頂點按照拓撲序列排列
if (level[t] < 0)
return flow;//如果bfs失敗,說明沒有路了
int temp;
while ( (temp = dfs(s,t,INF)) > 0){
flow += temp;
}
}
}
int main()
{
while (~scanf("%d %d",&N,&M)){
init();
for (int i = 1; i <= N; i++){
int tempa,tempb;
scanf("%d %d",&tempa,&tempb);
addedge(0,i,tempa,0);
addedge(i,N+1, tempb,0);
}
for (int i = 1; i <= M; i++){
int temp1,temp2,temp3;
scanf("%d %d %d",&temp1,&temp2,&temp3);
addedge(temp1,temp2,temp3,temp3);
}
printf("%d\n",max_flow(0,N+1));
}
return 0;
}
/*
3 1
1 10
2 10
10 3
2 3 1000
3 1
1 10
2 10
10 3
2 3 1000
*/