【bzoj4108】[Wf2015]Catering 有上下界费用流
原文地址:http://www.cnblogs.com/GXZlegend/p/6832537.html
题目描述
有一家装备出租公司收到了按照时间顺序排列的n个请求.
这家公司有k个搬运工.每个搬运工可以搬着一套装备按时间顺序去满足一些请求.一个搬运工从第i个请求的位置把东西搬到第j个请求的位置需要一些费用.公司的编号是1,请求的编号是2到n+1.所有搬运工必需从公司出发.
求满足所有请求所需的最小搬运费用.
输入
有可能有多组数据.(实际上没有)
第一行两个正整数n,k.
接下来n行,第i行有n-i+1个数.第j个数表示把装备从i搬到i+j的花费.
输出
输出一行一个整数表示最小花费.
样例输入
1 1
10
样例输出
10
题目大意
给定一个竞赛图,边有边权且方向总是由编号小指向编号大。给你k次机会从1沿边走向其它点,要求除1以外的每个点都需要且只能经过一次,问最小的边权之和。
题解
有上下界费用流,难在翻译题目
将每个点拆成两个,之间连边,上下界均为1。
用一个单独的点连向1限制流量,再加入两点之间的边。
然后求有上下界费用流。
另:并没有多组测试数据
#include <cstdio> #include <cstring> #include <queue> #define inf 0x3f3f3f3f using namespace std; queue<int> q; int head[300] , to[100000] , val[100000] , cost[100000] , next[100000] , cnt = 1 , s , t , dis[300] , from[300] , pre[300]; 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 += k * dis[t]; for(i = t ; i != s ; i = from[i]) val[pre[i]] -= k , val[pre[i] ^ 1] += k; } return ans; } int main() { int n , k , i , j , x; scanf("%d%d" , &n , &k); s = 2 * n + 2 , t = 2 * n + 3 , add(0 , 1 , k , 0); for(i = 2 ; i <= n + 1 ; i ++ ) scanf("%d" , &x) , add(1 , i , inf , x) , add(s , i + n , 1 , 0) , add(i , t , 1 , 0) , add(i + n , 0 , inf , 0); for(i = 2 ; i <= n ; i ++ ) for(j = i + 1 ; j <= n + 1 ; j ++ ) scanf("%d" , &x) , add(i + n , j , inf , x); printf("%d\n" , mincost()); return 0; }