蛋糕分发 - summer camp
Posted ccut-ry
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蛋糕分发 - summer camp相关的知识,希望对你有一定的参考价值。
题目描述:
恬恬的生日临近了。宇扬给她准备了一个大 蛋糕。
正如往常一样,宇扬在蛋糕上插了nnn支蜡烛,并把蛋糕分为mmm个区域。因为某种原因,他必须把第iii根蜡烛插在第aia\_iai?个区域或第bib\_ibi?个区域。区域之间是不相交的。宇扬在一个区域内同时摆放xxx支蜡烛就要花费x2x^2x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。
宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?
输入:
第一行包含两个整数nnn,mmm(1≤n≤501 le n le 501≤n≤50, 2≤m≤502le mle 502≤m≤50)。
接下来nnn行,每行两个整数ai,bia\_i,b\_iai?,bi?(1≤ai,bi≤m1 le a\_i, b\_i le m1≤ai?,bi?≤m)。
输出:
一个整数表示答案。
3 3
1 2
1 2
1 2
5
题目描述:
恬恬的生日临近了。宇扬给她准备了一个大 蛋糕。
正如往常一样,宇扬在蛋糕上插了nnn支蜡烛,并把蛋糕分为mmm个区域。因为某种原因,他必须把第iii根蜡烛插在第aia\_iai?个区域或第bib\_ibi?个区域。区域之间是不相交的。宇扬在一个区域内同时摆放xxx支蜡烛就要花费x2x^2x2的时间。宇扬布置蛋糕所用的总时间是他在每个区域花的时间的和。
宇扬想快些见到恬恬,你能告诉他布置蛋糕最少需要多少时间吗?
输入:
第一行包含两个整数nnn,mmm(1≤n≤501 le n le 501≤n≤50, 2≤m≤502le mle 502≤m≤50)。
接下来nnn行,每行两个整数ai,bia\_i,b\_iai?,bi?(1≤ai,bi≤m1 le a\_i, b\_i le m1≤ai?,bi?≤m)。
输出:
一个整数表示答案。
题意 :
给你 n 根蜡烛,同时告诉你每根蜡烛可以插在哪个区域中,对于同一个区域内插入的蜡烛总的花费为此区域内蜡烛数量的平方,问最小的花费是多少
思路分析 :
贪心对于此问题是不正确的,考虑一下网络流建图
考虑费用流时把每个part拆成n个点,选择第i个点的代表为放置i块蛋糕和(i - 1)块蛋糕的时间差,这个时间差是递增的,因此在费用流的过程中必定会从小到大选择
具体建图:左边n个点代表n个蛋糕,右边m * n个点代表m个part,每个part拆成n个点。源点向每个左边的点连一条流量1费用0的边,每个右边的点向汇点连一条流量1费用0的编。每个蛋糕向可以放的两个part的所有点连边,连向第i个点的费用为i^2 - (i - 1)^2,流量为1。这样求最小费用流既为答案。
代码示例 :
#include <bits/stdc++.h> using namespace std; const int maxn = 1e4; const int maxm = 1e5; const int inf = 0x3f3f3f3f; struct Edge { int to,next,flow,cost; // flow 表示水现有的流量 }edge[maxm]; int head[maxn],tol; int pre[maxn],dis[maxn]; bool vis[maxn]; int N; //节点个数,编号0->N-1 !全局变量 需要init赋值或主函数改变 void init(int n) { N=n; tol = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,int cost) //边起点,终点,流量,费用 { edge[tol].to = v; edge[tol].cost = cost; edge[tol].flow = cap; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cost = -cost; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } bool spfa(int s,int t) //单源最短路径算法 可判断负环 { queue<int >q; for(int i=0;i<N;i++) { dis[i] = inf; vis[i] = false; pre[i] = -1; } dis[s] = 0; vis[s] = true; q.push(s); while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i=head[u];i!=-1;i=edge[i].next) { int v= edge[i].to; if(edge[i].flow && dis[v]>dis[u]+edge[i].cost) { dis[v] = dis[u] + edge[i].cost; pre[v] = i; if(!vis[v]) { vis[v] = true; q.push(v); } } } } if(pre[t]==-1) return false; else return true; } int MCMF(int s,int t,int &cost) //MinCostMaxFlow 返回最大流,cost存最小费用 { int flow = 0; cost = 0; while(spfa(s,t)) { int Min = inf; for(int i= pre[t];i!=-1;i=pre[edge[i^1].to]) { if(Min>edge[i].flow) Min=edge[i].flow; } for(int i= pre[t];i!=-1;i=pre[edge[i^1].to]) { edge[i].flow -= Min; edge[i^1].flow +=Min; cost += edge[i].cost*Min; } flow += Min; } //printf("++++ %d %d ", flow, tol); return flow; } int n, m; int main() { int a, b; cin >> n >> m; init(n+m+2); for(int i = 1; i <= n; i++){ scanf("%d%d", &a, &b); addedge(0, i, 1, 0); addedge(i, n+a, 1, 0); addedge(i, n+b, 1, 0); } for(int i = n+1; i <= n+m; i++){ for(int j = 1; j <= 99; j += 2){ addedge(i, n+m+1, 1, j); } } int ans; MCMF(0, n+m+1, ans); printf("%d ", ans); return 0; }
以上是关于蛋糕分发 - summer camp的主要内容,如果未能解决你的问题,请参考以下文章
Petrozavodsk Summer Training Camp 2017
BZOJ4896 [Thu Summer Camp2016]补退选
CCPC-Wannafly Summer Camp 2019 全记录