标签:min 个人 世界 cpp 接下来 empty sizeof 个数 com
原文地址:http://www.cnblogs.com/GXZlegend
题目描述
输入
输出
在第一行输出最少的总费用。
样例输入
6 3
2 1 3 1 2 1
2 6 8 5 0
8 2 4 1
6 1 0
4 -1
4
样例输出
27
题解
有上下界费用流
题目中说每个点需要经过固定的次数,那么我们可以拆点,并在拆出来的两个点之间连一条上下界均为vi的边。
建图通法可以参考 bzoj3786 ,对于这道题的具体建图方法:
2*n+1->0(m,0)(用于限制流量)
0->i(inf,0)
i+n->2*n+1(inf,0)(将有源汇转化为无源汇)
s->i+n(vi,0),i->t(vi,0)
i+n->j(inf,cost[i][j])(i<j)
#include <cstdio>
#include <cstring>
#include <queue>
#define inf 0x3f3f3f3f
using namespace std;
queue<int> q;
int head[210] , to[500010] , val[500010] , cost[500010] , next[500010] , cnt = 1 , cd[210] , s , t , dis[210] , from[210] , pre[210];
void add(int x , int y , int v , int c)
{
to[++cnt] = y , val[cnt] = v , cost[cnt] = c , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , cost[cnt] = -c , next[cnt] = head[y] , head[y] = cnt;
}
bool spfa()
{
int x , i;
memset(dis , 0x3f , sizeof(dis));
memset(from , -1 , sizeof(from));
dis[s] = 0 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
if(val[i] && dis[to[i]] > dis[x] + cost[i])
dis[to[i]] = dis[x] + cost[i] , from[to[i]] = x , pre[to[i]] = i , q.push(to[i]);
}
return ~from[t];
}
int mincost()
{
int ans = 0 , i , k;
while(spfa())
{
k = inf;
for(i = t ; i != s ; i = from[i]) k = min(k , val[pre[i]]);
ans += dis[t] * k;
for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k;
}
return ans;
}
int main()
{
int n , m , i , j , x;
scanf("%d%d" , &n , &m) , s = 2 * n + 2 , t = 2 * n + 3;
add(2 * n + 1 , 0 , m , 0);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , add(0 , i , inf , 0) , add(i + n , 2 * n + 1 , inf , 0) , add(s , i + n , x , 0) , add(i , t , x , 0);
for(i = 1 ; i <= n ; i ++ )
{
for(j = i + 1 ; j <= n ; j ++ )
{
scanf("%d" , &x);
if(~x) add(i + n , j , inf , x);
}
}
printf("%d\n" , mincost());
return 0;
}
标签:min 个人 世界 cpp 接下来 empty sizeof 个数 com
原文地址:http://www.cnblogs.com/GXZlegend/p/6832385.html