1061: [Noi2008]志愿者招募
Description
申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人。 布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最优的招募方案。Input
第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。 接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。 接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。Output
仅包含一个整数,表示你所设计的最优方案的总费用。
Sample Input
3 3
2 3 4
1 2 2
2 3 5
3 3 2Sample Output
14HINT
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。
Source
【分析】
表示初看觉得这题很经典但是仔细想想发现我不会ORZ。。
表示不会单纯形法搞线性规划【要学么?
之前做的网络流24题都没有涉及到线性规划的转化的。。
这道的确是经典题,但是转化挺难的。。
推荐博客!!https://www.byvoid.com/zhs/blog/noi-2008-employee#more-916
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define Maxn 1010 9 #define Maxm 10010 10 #define INF 0xfffffff 11 12 int mymin(int x,int y) {return x<y?x:y;} 13 14 int n,m; 15 16 struct node 17 { 18 int x,y,f,c,o,next; 19 }t[4*Maxm]; 20 int first[Maxn],len; 21 22 void ins(int x,int y,int f,int c) 23 { 24 t[++len].x=x;t[len].y=y;t[len].f=f;t[len].c=c;t[len].o=len+1; 25 t[len].next=first[x];first[x]=len; 26 t[++len].x=y;t[len].y=x;t[len].f=0;t[len].c=-c;t[len].o=len-1; 27 t[len].next=first[y];first[y]=len; 28 } 29 30 int nd[Maxn]; 31 int dis[Maxn],flow[Maxn],pre[Maxn],st,ed; 32 bool inq[Maxn]; 33 queue<int > q; 34 35 void bfs() 36 { 37 while(!q.empty()) q.pop(); 38 // memset(dis,-1,sizeof(dis)); 39 for(int i=1;i<=ed;i++) dis[i]=INF; 40 memset(inq,0,sizeof(inq)); 41 dis[st]=0;inq[st]=1;q.push(st); 42 flow[st]=INF; 43 while(!q.empty()) 44 { 45 int x=q.front(); 46 for(int i=first[x];i;i=t[i].next) if(t[i].f>0) 47 { 48 int y=t[i].y; 49 if(dis[y]>dis[x]+t[i].c) 50 { 51 dis[y]=dis[x]+t[i].c; 52 pre[y]=i; 53 flow[y]=mymin(flow[x],t[i].f); 54 if(!inq[y]) 55 { 56 q.push(y); 57 inq[y]=1; 58 } 59 } 60 } 61 q.pop();inq[x]=0; 62 } 63 } 64 65 void max_flow() 66 { 67 int sum=0; 68 while(1) 69 { 70 bfs(); 71 if(dis[ed]==INF) break; 72 sum+=dis[ed]*flow[ed]; 73 int x=ed; 74 while(x!=st) 75 { 76 t[pre[x]].f-=flow[ed]; 77 t[t[pre[x]].o].f+=flow[ed]; 78 x=t[pre[x]].x; 79 } 80 } 81 printf("%d ",sum); 82 } 83 84 void output() 85 { 86 for(int i=1;i<=len;i+=2) 87 { 88 printf("%d -> %d = %d , %d ",t[i].x,t[i].y,t[i].f,t[i].c); 89 } 90 } 91 92 int main() 93 { 94 scanf("%d%d",&n,&m); 95 len=0; 96 for(int i=1;i<=n;i++) scanf("%d",&nd[i]); 97 memset(first,0,sizeof(first)); 98 for(int i=1;i<=m;i++) 99 { 100 int l,r,c; 101 scanf("%d%d%d",&l,&r,&c); 102 ins(l,r+1,INF,c); 103 } 104 for(int i=1;i<=n;i++) ins(i+1,i,INF,0); 105 nd[0]=0; 106 st=n+2;ed=st+1; 107 for(int i=1;i<=n;i++) if(nd[i]-nd[i-1]>0) ins(st,i,nd[i]-nd[i-1],0); 108 else if(nd[i]-nd[i-1]<0) ins(i,ed,nd[i-1]-nd[i],0); 109 ins(n+1,ed,nd[n],0); 110 // output(); 111 max_flow(); 112 return 0; 113 }
建图超机智的,我想不到啊!!
2017-02-25 10:55:41
【今天我要用单纯形水这题】
【趁我还记得模板怎么背】
【---需要初始化版本】
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<ctime> 7 using namespace std; 8 #define Maxm 1010 9 #define Maxn 10010 10 const double eps=1e-9,INF=1e15; 11 12 int m,n; 13 14 double a[Maxm][Maxn]; 15 // int id[Maxn*2]; 16 17 double myabs(double x) {return x>0?x:-x;} 18 19 void Pivot(int l,int e) 20 { 21 // swap(id[l+n],id[e]); 22 double t=a[l][e];a[l][e]=1; 23 for(int j=0;j<=n;j++) a[l][j]/=t; 24 for(int i=0;i<=m;i++) if(i!=l&&myabs(a[i][e])>eps) 25 { 26 t=a[i][e];a[i][e]=0; 27 for(int j=0;j<=n;j++) a[i][j]-=a[l][j]*t; 28 } 29 } 30 31 bool init() 32 { 33 while(1) 34 { 35 int l=0,e=0; 36 for(int i=1;i<=m;i++) if(a[i][0]<-eps&&(!l||(rand()&1))) l=i; 37 if(!l) break; 38 for(int j=1;j<=n;j++) if(a[l][j]<-eps&&(!e||(rand()&1))) e=j; 39 if(!e) return 0; 40 Pivot(l,e); 41 } 42 return 1; 43 } 44 45 bool simplex() 46 { 47 while(1) 48 { 49 int l=0,e=0;double mn=INF; 50 for(int j=1;j<=n;j++) if(a[0][j]>eps) {e=j;break;} 51 if(!e) break; 52 for(int i=1;i<=m;i++) if(a[i][e]>eps&&mn>a[i][0]/a[i][e]) 53 mn=a[i][0]/a[i][e],l=i; 54 if(!l) return 0; 55 Pivot(l,e); 56 } 57 return 1; 58 } 59 60 int main() 61 { 62 srand(2333); 63 scanf("%d%d",&m,&n); 64 for(int i=1;i<=m;i++) {scanf("%lf",&a[i][0]);a[i][0]=-a[i][0];} 65 for(int i=1;i<=n;i++) 66 { 67 int s,t; 68 scanf("%d%d%lf",&s,&t,&a[0][i]);a[0][i]=-a[0][i]; 69 for(int j=s;j<=t;j++) a[j][i]=-1; 70 } 71 if(init()&&simplex()) 72 { 73 printf("%.0lf ",a[0][0]); 74 } 75 else printf("-1 "); 76 return 0; 77 }
【对偶版本,不需要初始化,快10s!!!】
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<ctime> 7 using namespace std; 8 #define Maxm 1010 9 #define Maxn 10010 10 const double eps=1e-9,INF=1e15; 11 12 int m,n; 13 14 double a[Maxn][Maxm]; 15 // double a[Maxm][Maxn]; 16 // int id[Maxn*2]; 17 18 double myabs(double x) {return x>0?x:-x;} 19 20 void Pivot(int l,int e) 21 { 22 // swap(id[l+n],id[e]); 23 double t=a[l][e];a[l][e]=1; 24 for(int j=0;j<=n;j++) a[l][j]/=t; 25 for(int i=0;i<=m;i++) if(i!=l&&myabs(a[i][e])>eps) 26 { 27 t=a[i][e];a[i][e]=0; 28 for(int j=0;j<=n;j++) a[i][j]-=a[l][j]*t; 29 } 30 } 31 32 bool init() 33 { 34 while(1) 35 { 36 int l=0,e=0; 37 for(int i=1;i<=m;i++) if(a[i][0]<-eps&&(!l||(rand()&1))) l=i; 38 if(!l) break; 39 for(int j=1;j<=n;j++) if(a[l][j]<-eps&&(!e||(rand()&1))) e=j; 40 if(!e) return 0; 41 Pivot(l,e); 42 } 43 return 1; 44 } 45 46 bool simplex() 47 { 48 while(1) 49 { 50 int l=0,e=0;double mn=INF; 51 for(int j=1;j<=n;j++) if(a[0][j]>eps) {e=j;break;} 52 if(!e) break; 53 for(int i=1;i<=m;i++) if(a[i][e]>eps&&mn>a[i][0]/a[i][e]) 54 mn=a[i][0]/a[i][e],l=i; 55 if(!l) return 0; 56 Pivot(l,e); 57 } 58 return 1; 59 } 60 61 int main() 62 { 63 srand(2333); 64 scanf("%d%d",&m,&n); 65 for(int i=1;i<=m;i++) {scanf("%lf",&a[0][i]);a[0][i]=a[0][i];} 66 for(int i=1;i<=n;i++) 67 { 68 int s,t; 69 scanf("%d%d%lf",&s,&t,&a[i][0]);a[i][0]=a[i][0]; 70 for(int j=s;j<=t;j++) a[i][j]=1; 71 } 72 swap(n,m); 73 if(/*init()&&*/simplex()) 74 { 75 printf("%.0lf ",-a[0][0]); 76 } 77 else printf("-1 "); 78 return 0; 79 }
对偶就是i和j反,系数正负全反。。。