线性规划||网络流(费用流):COGS 288. [NOI2008] 志愿者招募
2016-03-25 19:30
561 查看
[NOI2008] 志愿者招募
输入文件:employee.in输出文件:
employee.out简单对比
时间限制:2 s
内存限制:512 MB
【问题描述】
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人。
布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci
元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最
优的招募方案。
【输入格式】
输入文件的第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。
接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。
接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。
【输出格式】
输入文件中仅包含一个整数,表示你所设计的最优方案的总费用。
【输入样例】
3 3
2 3 4
1 2 2
2 3 5
3 3 2
【输出样例】
14
【样例说明】
招募3 名第一类志愿者和4 名第三类志愿者。
【数据规模和约定】
30%的数据中,1 ≤ N, M ≤ 10,1 ≤ Ai ≤ 10;
100%的数据中,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均
不超过2^31-1。
https://www.byvoid.com/zhs/blog/noi-2008-employee
#include <iostream> #include <cstring> #include <cstdio> #include <queue> using namespace std; const int INF=100000010; const int maxn=11010; const int maxm=100010; int cnt=1,fir[maxn],to[maxm],nxt[maxm],cap[maxm],val[maxm]; void addedge(int a,int b,int c,int v){ nxt[++cnt]=fir[a];to[cnt]=b;cap[cnt]=c;val[cnt]=v;fir[a]=cnt; } int N,M,S,T; int dis[maxn],path[maxn],tot[maxn],vis[maxn]; queue<int>q; int MCMF(){ int ret=0; while(true){ memset(dis,127,sizeof(dis));dis[S]=0; q.push(S);vis[S]=1; while(!q.empty()){ int node=q.front();q.pop();vis[node]=0; for(int i=fir[node];i;i=nxt[i]) if(cap[i]&&dis[to[i]]>dis[node]+val[i]){ dis[to[i]]=dis[node]+val[i]; path[to[i]]=i; if(!vis[to[i]]){ vis[to[i]]=1; q.push(to[i]); } } } if(dis[T]==2139062143) break; int p=T,f=INF; while(p!=S){ f=min(f,cap[path[p]]); p=to[path[p]^1]; } ret+=dis[T]*f;p=T; while(p!=S){ cap[path[p]]-=f; cap[path[p]^1]+=f; p=to[path[p]^1]; } } return ret; } int main(){ freopen("employee.in","r",stdin); freopen("employee.out","w",stdout); scanf("%d%d",&N,&M); S=0;T=N+2; for(int i=1;i<=N;i++) scanf("%d",&tot[i]); for(int i=1,a,b,c;i<=M;i++){ scanf("%d%d%d",&a,&b,&c); addedge(a,b+1,INF,c); addedge(b+1,a,0,-c); } for(int i=1;i<=N+1;i++){ int c=tot[i]-tot[i-1]; if(c>0){ addedge(S,i,c,0); addedge(i,S,0,0); } if(c<0){ addedge(i,T,-c,0); addedge(T,i,0,0); } if(i>1){ addedge(i,i-1,INF,0); addedge(i-1,i,0,0); } } printf("%d\n",MCMF()); return 0; }
然后又用线性规划。
额,松弛型先天不足,数组开不了,无法通过,再学一下吧。
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; const int maxr=11010; const int maxc=1010; const double eps=1e-10; int n,m,nxt[maxc]; int N[maxr],B[maxr]; double a[maxr][maxr],v; double b[maxr],c[maxr]; int SGN(double x){ return (x>eps)-(x<-eps); } void Init(){ B[0]=N[0]=0;v=0.0; for(int i=1;i<=n;i++)N[++N[0]]=i; for(int i=1;i<=m;i++)B[++B[0]]=i+n; } void Pivot(int l,int e){ b[e]=b[l]/a[l][e]; a[e][l]=1.0/a[l][e]; for(int i=1;i<=N[0];i++) if(N[i]!=e)a[e][N[i]]=a[l][N[i]]/a[l][e]; int pre=0; for(int i=1;i<=N[0];i++) if(N[i]!=e&&SGN(a[e][N[i]])!=0) {nxt[pre]=i;pre=i;} nxt[pre]=0; for(int i=1;i<=B[0];i++) if(B[i]!=l){ b[B[i]]-=a[B[i]][e]*b[e]; a[B[i]][l]=-a[B[i]][e]*a[e][l]; for(int j=nxt[0];j;j=nxt[j]) if(N[j]!=e)a[B[i]][N[j]]-=a[B[i]][e]*a[e][N[j]]; } v+=c[e]*b[e]; c[l]=-c[e]*a[e][l]; for(int i=1;i<=N[0];i++) if(N[i]!=e) c[N[i]]-=c[e]*a[e][N[i]]; for(int i=1;i<=N[0];i++)if(N[i]==e)N[i]=l; for(int i=1;i<=B[0];i++)if(B[i]==l)B[i]=e; } void Simplex(){ while(true){ int e=maxr,l=maxr; for(int i=1;i<=N[0];i++) if(SGN(c[N[i]])>0&&e>N[i])e=N[i]; if(e==maxr)break; double lam=-1; for(int i=1;i<=B[0];i++) if(SGN(a[B[i]][e])>0){ double tmp=b[B[i]]/a[B[i]][e]; if(lam==-1||SGN(lam-tmp)>0||SGN(lam-tmp)==0&&l>B[i]) {lam=tmp;l=B[i];} } Pivot(l,e); } } int main(){ #ifndef ONLINE_JUDGE freopen("employee.in","r",stdin); freopen("employee.out","w",stdout); #endif scanf("%d%d",&n,&m); for(int i=1,t;i<=n;i++){ scanf("%d",&t); c[i]=t; } for(int i=1,l,r,t;i<=m;i++){ scanf("%d%d%d",&l,&r,&t); for(int j=l;j<=r;j++) a[i+n][j]=1; b[i+n]=t; } Init(); Simplex(); printf("%d\n",(int)(v+0.5)); return 0; }
这个程序可以AC,但解法并不具有共性啊……
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int maxr=10010; const int maxc=1010; int n,m,nxt[maxc]; int a[maxr][maxc]; void Pivot(int l,int e){ int pre=maxc-1; for(int i=0;i<=n;i++) if(a[l][i]!=0){nxt[pre]=i;pre=i;} nxt[pre]=-1; for(int i=0,t;i<=m;i++) if(i!=l&&(t=a[i][e])){ a[i][e]=0; for(int j=nxt[maxc-1];j!=-1;j=nxt[j]) a[i][j]+=t*a[l][j]; } } void Simplex(){ while(true){ int e=0,l=0; for(int i=1;i<=n;i++) if(a[0][i]>0){e=i;break;} if(e==0)break; for(int i=1;i<=m;i++) if(a[i][e]<0&&(!l||a[l][0]>a[i][0])) {l=i;} Pivot(l,e); } } int main(){ #ifndef ONLINE_JUDGE freopen("employee.in","r",stdin); freopen("employee.out","w",stdout); #endif scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[0][i]); for(int i=1,l,r,t;i<=m;i++){ scanf("%d%d%d",&l,&r,&t); for(int j=l;j<=r;j++) a[i][j]=-1; a[i][0]=t; } Simplex(); printf("%d\n",a[0][0]); return 0; }
这里的线性规划式子都是原式的对偶线性规划式。
相关文章推荐
- TCP协议中的三次握手和四次挥手图解
- 20159302《网络攻击与防范》第四周学习总结
- 地址栏传参到action中文出现乱码的问题http://group.gimoo.net/review/96719
- 网络流入门—用于最大流的Dinic算法
- 最简单的二进制神经网络
- TCP连接终止前的TIME_WAIT状态
- http服务配置/LAMP网站平台/PHP应用部署(Discuz!论坛系统
- windows快捷键之打开网络连接
- PHP header函数设置http报文头示例详解
- 快速安装 GitLab 并汉化
- 加载网络图片保存到本地java.io.IOException: open failed: EINVAL (Invalid argument)
- 采用HttpURLConnection的POST方式实现登陆案例
- 在ifcfg文件中写上gateway网络不通的解决方法
- PHP 学习日志——httpd.conf
- 浅谈Volley网络框架(二)
- 下载网络文件HttpURLConnection.getContentLength()大小为 0
- 高并发socket/tcp网络最大连接数所受的限制问题,ulimit文件打开数,文件描述符
- 使用httpclient必须知道的参数设置及代码写法、存在的风险
- XMLHttpRequest API
- 虚拟机centos网络配置