题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1497
题目大意:有n个客户和m个中转站,每个客户要使用两个中转站,同时会给你一些收益;然而打开一个中转站需要一些成本,求最大获利。
一眼网络流……建图方法:
建立一个源点,源点连到所有客户,流量为收益,客户连接到他要使用的中转站,流量为INF,所有中转站连向汇点,流量为成本,跑最大流即可。
为什么这样建图呢?请用最小割定理:设最大流为你要失去的利润,割左边表示不给这个客户服务,割右边则代表你支付成本来建立这个中转站(不管怎么样都有花费……),然后用所有客户的收益和减去最大流就是结果~
裸的Dinic扔上去果断TLE……你需要一个当前弧优化,当前弧优化是什么呢?
Dinic不是有个dfs过程吗?每次从头搜索太麻烦了,所以记录一个当前搜到哪条边了,下次dfs的时候直接从这条边继续往下搜就是,速度瞬间涨上去啦~\(≧▽≦)/~
#include <iostream>
#include <cstdio>
#include <queue>
#define INF 214748364
using namespace std;
struct Link
{
int s,t,c,next;
}l[1000000];
int g[100000];
int cnt[100000];
int dist[100000];
queue<int> Q;
int n,m;
bool bfs(int x,int y)
{
Q.push(x);
dist[x] = 1;
while(!Q.empty())
{
int p = Q.front();
int w = g[p];
while(w)
{
if(l[w].c && !dist[l[w].t])
{
dist[l[w].t] = dist[p] + 1;
Q.push(l[w].t);
}
w = l[w].next;
}
Q.pop();
}
return dist[y];
}
int dfs(int x,int t,int flow)
{
if(x == t || flow == 0)
return flow;
int w = cnt[x];
while(w)
{
if(dist[l[w].t] == dist[x] + 1)
{
int k = dfs(l[w].t,t,min(flow,l[w].c));
if(k)
{
cnt[x] = w;
l[w].c -= k;
l[w^1].c += k;
return k;
}
}
w = l[w].next;
}
return 0;
}
int maxflow(int s,int t)
{
int flow = 0;
while(bfs(s,t))
{
while(233)
{
int w = dfs(s,t,INF);
flow += w;
if(w == 0)
break;
}
for(int i = 0;i <= n+m+1;i ++)
{
cnt[i] = g[i];
dist[i] = 0;
}
}
return flow;
}
void Add_Link(int s,int t,int c,int x)
{
l[x].s = s;
l[x].t = t;
l[x].c = c;
l[x].next = g[s];
g[s] = x;
l[x^1].s = t;
l[x^1].t = s;
l[x^1].c = 0;
l[x^1].next = g[t];
g[t] = x^1;
return ;
}
int read()
{
int x = 0;
char w;
w = getchar();
while(w <= '9' && w >= '0')
{
x *= 10;
x += w;
x -= '0';
w = getchar();
}
return x;
}
int main()
{
int x,y,z,p = 0,sum = 0;
n = read();
m = read();
for(int i = 1;i <= n;i ++)
{
x = read();
p += 2;
Add_Link(m+i,m+n+1,x,p);
}
getchar(); //这行数据多个空格= =
for(int i = 1;i <= m;i ++)
{
x = read();
y = read();
z = read();
p += 2;
Add_Link(i,m+x,INF,p);
p += 2;
Add_Link(i,m+y,INF,p);
p += 2;
Add_Link(0,i,z,p);
sum += z;
}
cout << sum - maxflow(0,n+m+1);
return 0;
}