想必大家都看过成龙大哥的《80天环游世界》,里面的紧张刺激的打斗场面一定给你留下了深刻的印象。现在就有这么
一个80人的团伙,也想来一次环游世界。
他们打算兵分多路,游遍每一个国家。
因为他们主要分布在东方,所以他们只朝西方进军。设从东方到西方的每一个国家的编号依次为1...N。假若第i个人的游历路线为P1、P2......Pk(0≤k≤N),则P1
众所周知,中国相当美丽,这样在环游世界时就有很多人经过中国。我们用一个正整数Vi来描述一个国家的吸引程度,Vi值越大表示该国家越有吸引力,同时也表示有且仅
有Vi个人会经过那一个国家。
为了节省时间,他们打算通过坐飞机来完成环游世界的任务。同时为了省钱,他们希望总的机票费最小。
明天就要出发了,可是有些人临阵脱逃,最终只剩下了M个人去环游世界。他们想知道最少的总费用,你能告诉他们吗?
Input
第一行两个正整数N,M。
第二行有N个不大于M正整数,分别表示V1,V2......VN。
接下来有N-1行。第i行有N-i个整数,该行的第j个数表示从第i个国家到第i+j个国家的机票费(如果该值等于-1则表示这两个国家间没有通航)。
Output
在第一行输出最少的总费用。
Sample Input
6 3
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4
Sample Output
27
HINT
1<= N < =100 1<= M <= 79
Source
转换模型,,等价于求有上下界的最小费用可行流
每个国家拆成两个点Ai,Bi,中间连上下界都为Vi的边
假设一个源点s,城市0,s向0连一条容量为m的边,0向所有城市的Ai连容量为INF的边
所有城市的Bi向汇点t连容量为INF的边,城市间的飞机就有Bi向Aj连边,容量INF,有费用
只要再连(t,s,INF)这条边就能构成循环流了,按照构建循环流的方法,跑一遍最小费用最大流就是答案了
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn = 255;
const int maxm = 4E5 + 40;
const int INF = ~0U>>1;
struct E{
int to,cap,flow,cost; E(){}
E(int to,int cap,int flow,int cost):
to(to),cap(cap),flow(flow),cost(cost){}
}edgs[maxm];
int n,m,s,t,S,T,cnt,Cnt,from[maxn],flow[maxn],cost[maxn];
bool vis[maxn];
vector v[maxn];
queue Q;
void Add(int x,int y,int cap,int cost)
{
v[x].push_back(cnt); edgs[cnt++] = E(y,cap,0,cost);
v[y].push_back(cnt); edgs[cnt++] = E(x,0,0,-cost);
}
bool SPFA()
{
for (int i = 0; i <= T; i++)
cost[i] = INF,vis[i] = 0;
vis[S] = 1; Q.push(S);
flow[S] = INF; cost[S] = 0;
while (!Q.empty())
{
int k = Q.front(); Q.pop(); vis[k] = 0;
for (int i = 0; i < v[k].size(); i++)
{
E e = edgs[v[k][i]];
if (e.cap == e.flow) continue;
if (cost[e.to] > cost[k] + e.cost)
{
cost[e.to] = cost[k] + e.cost;
flow[e.to] = min(flow[k],e.cap - e.flow);
from[e.to] = v[k][i];
if (!vis[e.to]) vis[e.to] = 1,Q.push(e.to);
}
}
}
return cost[T] != INF;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> n >> m; s = 2*n + 1; t = s + 1;
S = t + 1; T = S + 1; Add(s,0,m,0);
for (int i = 1; i <= n; i++)
{
int x; scanf("%d",&x);
Add(i,T,x,0); Add(S,i + n,x,0);
Add(0,i,INF,0); Add(i + n,t,INF,0);
}
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
{
int x; scanf("%d",&x);
if (x == -1) continue;
Add(i + n,j,INF,x);
}
Add(t,s,INF,0); int Ans = 0;
while (SPFA())
{
Ans += flow[T]*cost[T];
for (int x = T; x != S; x = edgs[from[x]^1].to)
{
edgs[from[x]].flow += flow[T];
edgs[from[x]^1].flow -= flow[T];
}
}
cout << Ans;
return 0;
}