[Noi2008]志愿者招募(BZOJ1061)
来源:互联网 发布:ummy mac 破解 编辑:程序博客网 时间:2024/05/21 02:33
相关链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=1061
题目大意:
输入
输出
仅包含一个整数,表示你所设计的最优方案的总费用。
样例输入
2 3 4
1 2 2
2 3 5
3 3 2
样例输出
提示
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
设雇佣第i类志愿者的人数为X[i],每个志愿者的费用为V[i],第j天雇佣的人数为P[j],则每天的雇佣人数应满足一个不等式,如上表所述,可以列出
P[1] = X[1] + X[2] >= 4
P[2] = X[1] + X[3] >= 2
P[3] = X[3] + X[4] +X[5] >= 5
P[4] = X[5] >= 3
对于第i个不等式,添加辅助变量Y[i] (Y[i]>=0) ,可以使其变为等式
P[1] = X[1] + X[2] - Y[1] = 4
P[2] = X[1] + X[3] - Y[2] = 2
P[3] = X[3] + X[4] +X[5] - Y[3] = 5
P[4] = X[5] - Y[4] = 3
在上述四个等式上下添加P[0]=0,P[5]=0,每次用下边的式子减去上边的式子,得出
① P[1] - P[0] = X[1] + X[2] - Y[1] = 4
② P[2] - P[1] = X[3] - X[2] -Y[2] +Y[1] = -2
③ P[3] - P[2] = X[4] + X[5] - X[1] - Y[3] + Y[2] =3
④ P[4] - P[3] = - X[3] - X[4] + Y[3] - Y[4] = -2
⑤ P[5] - P[4] = - X[5] + Y[4] = -3
观察发现,每个变量都在两个式子中出现了,而且一次为正,一次为负。所有等式右边和为0。接下来,根据上面五个等式构图。
- 每个等式为图中一个顶点,添加源点S和汇点T。
- 如果一个等式右边为非负整数c,从源点S向该等式对应的顶点连接一条容量为c,权值为0的有向边;如果一个等式右边为负整数c,从该等式对应的顶点向汇点T连接一条容量为c,权值为0的有向边。
- 如果一个变量X[i]在第j个等式中出现为X[i],在第k个等式中出现为-X[i],从顶点j向顶点k连接一条容量为∞,权值为V[i]的有向边。
- 如果一个变量Y[i]在第j个等式中出现为Y[i],在第k个等式中出现为-Y[i],从顶点j向顶点k连接一条容量为∞,权值为0的有向边。
构图以后,求从源点S到汇点T的最小费用最大流,费用值就是结果。
附代码:#include <iostream>#include <stdio.h>#include <stdlib.h>#include <algorithm>#include <string.h>#include <math.h>#include <queue>using namespace std;const int MAXN=500;const int INF=1684300900;struct node{ int x,y,next,cost,op,d;}e[MAXN*100];int first[MAXN*100],pre[MAXN*100];int n,m,tot,S,T,ans;int a[MAXN*5],d[MAXN*5];bool b[MAXN*5];queue<int> q;void Add(int x,int y,int c,int d){ e[++tot].y=y; e[tot].x=x; e[tot].d=d; e[tot].cost=c; e[tot].op=tot+1; e[tot].next=first[x]; first[x]=tot; e[++tot].y=x; e[tot].x=y; e[tot].d=0; e[tot].cost=-c; e[tot].op=tot-1; e[tot].next=first[y]; first[y]=tot;}void Init(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;++i) scanf("%d",&a[i]); for (int i=1;i<=m;++i) { int x,y,z; scanf("%d%d%d",&x,&y,&z); Add(x,y+1,z,INF); } S=0,T=n+2; for (int i=1;i<=n+1;++i) { int temp=a[i]-a[i-1]; if (temp>0) Add(S,i,0,temp); else Add(i,T,0,-temp); if (i>1) Add(i,i-1,0,INF); }}void init(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); Add(x,y+1,z,INF); } S=0; T=n+2; for(int i=1;i<=n+1;i++) { int temp=a[i]-a[i-1]; if(temp>0) Add(S,i,0,temp); else Add(i,T,0,-temp); if(i>1) Add(i,i-1,0,INF); }}bool SPFA(){ memset(b,0,sizeof(b)); memset(d,100,sizeof(d)); d[S]=0,b[S]=1,q.push(S),pre[S]=-1; while (!q.empty()) { int u=q.front(); b[u]=0,q.pop(); for (int i=first[u];i;i=e[i].next) if (d[e[i].y]>d[u]+e[i].cost && e[i].d>0) { d[e[i].y]=d[u]+e[i].cost; pre[e[i].y]=i; if (!b[e[i].y]) { b[e[i].y]=1; q.push(e[i].y); } } } return d[T]<INF;}void Find(){ int Min=INF; for (int i=pre[T];i!=-1;i=pre[e[i].x]) Min=min(Min,e[i].d); for (int i=pre[T];i!=-1;i=pre[e[i].x]) { e[i].d-=Min; e[e[i].op].d+=Min; ans+=Min*e[i].cost; }}int main(){ init(); while (SPFA()) Find(); printf("%d\n",ans);return 0;}
- [Noi2008]志愿者招募(BZOJ1061)
- [BZOJ1061][Noi2008]志愿者招募
- bzoj1061【NOI2008】志愿者招募
- 【NOI2008】【BZOJ1061】志愿者招募
- bzoj1061: [Noi2008]志愿者招募
- 【NOI2008】BZOJ1061志愿者招募
- [bzoj1061][NOI2008]志愿者招募
- BZOJ1061: [Noi2008]志愿者招募
- BZOJ1061: [Noi2008]志愿者招募
- 【bzoj1061】[Noi2008]志愿者招募
- bzoj1061: [Noi2008]志愿者招募
- bzoj1061: [Noi2008]志愿者招募
- 【NOI2008】bzoj1061 志愿者招募
- [bzoj1061][Noi2008]志愿者招募
- 【bzoj1061】 Noi2008—志愿者招募
- [BZOJ1061][NOI2008]志愿者招募(费用流神题单纯形裸题)
- bzoj1061 [Noi2008]志愿者招募 单纯形(模板)
- bzoj1061: [Noi2008]志愿者招募(最小费用最大流)
- JZOJ 4911 【NOIP2017模拟12.3】人生的叹息
- Ubuntu下OpenGrok的安装配置
- Hadoop的benchmark测试IO性能测试TestDFSIO测试时java.io.FileNotFoundException: TestDFSIO_results.log (Permission
- const用法详解
- 第十六周项目1--验证算法--(5)直接选择排序
- [Noi2008]志愿者招募(BZOJ1061)
- Android微信登录(shareSDK)注意事项
- Eclipse下创建安卓项目时Create Activity—Blank Activity不能下一步,也不能点完成
- LeetCode110:Balanced Binary Tree
- Android 如何改变TextView中个别字样式
- Java集合框架 之Collection接口
- 简单的 利用 parser 获取页面信息
- POJ 3421 X-factor Chains 已被翻译
- spring的事务管理