卧薪尝胆,厚积薄发。
AHOI2014/JSOI2014 支线剧情
Date: Wed Mar 20 10:07:41 CST 2019 In Category: NoCategory

Description:

给一个图,边有边权,要求每条边必须经过一次,求最小代价。
$1\leqslant n\leqslant300,1\leqslant m\leqslant 5000$

Solution:

有源汇有上下界最小费用可行流。
注意如果要强制流过的边有边权的话要事先加上。

Code:


// luogu-judger-enable-o2
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
int n;
int s,t,tt;
struct edge
{
int to,nxt,f,v;
}e[22010];
int edgenum = 0;
int lin[310];
inline void add(int a,int b,int c,int d)
{//cout << a << " " << b << " " << c << " " << d << endl;
e[edgenum] = (edge){b,lin[a],c,d};lin[a] = edgenum++;
e[edgenum] = (edge){a,lin[b],0,-d};lin[b] = edgenum++;
return;
}
int d[310],rate[310],pre[310];
bool v[310];
int ind[310];
inline bool SPFA()
{
memset(d,0x3f,sizeof(d));
queue<int> q;
q.push(s);
d[s] = 0;
rate[s] = INF;
while(!q.empty())
{
register int k = q.front();q.pop();
v[k] = false;
for(register int i = lin[k];i != -1;i = e[i].nxt)
{
if(d[e[i].to] > d[k] + e[i].v && e[i].f)
{
d[e[i].to] = d[k] + e[i].v;
rate[e[i].to] = min(rate[k],e[i].f);
pre[e[i].to] = i;
if(!v[e[i].to])
{
v[e[i].to] = true;
q.push(e[i].to);
}
}
}
}
return d[t] < INF;
}
inline int flow()
{
for(register int i = t;i != s;i = e[pre[i] ^ 1].to)
{//cout << i << endl;
e[pre[i]].f -= rate[t];
e[pre[i] ^ 1].f += rate[t];
}//cout << s << endl;cout << rate[t] << " " << d[t] << endl;
return rate[t] * d[t];
}
inline int EK()
{
register int ans = 0;
while(SPFA())ans += flow();
return ans;
}
inline int read()
{
register int res = 0;
register char c = getchar();
while(!isdigit(c))c = getchar();
while(isdigit(c))
{
res = (res << 3) + (res << 1) + c - '0';
c = getchar();
}
return res;
}
int main()
{
memset(lin,-1,sizeof(lin));
scanf("%d",&n);
tt = n + 1;s = tt + 1;t = s + 1;
int sum = 0;
register int k,x,y;
for(register int i = 1;i <= n;++i)
{
k = read();
add(i,tt,INF,0);
for(register int j = 1;j <= k;++j)
{
x = read();y = read();
add(i,x,INF,y);
--ind[i];++ind[x];
sum += y;
}
}
for(register int i = 1;i <= n;++i)
{
if(ind[i] > 0)add(s,i,ind[i],0);
if(ind[i] < 0)add(i,t,-ind[i],0);
}
add(tt,1,INF,0);
cout << EK() + sum << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡