【BZOJ 1061】 1061: [Noi2008]志愿者招募 (线性规划与网络流)**

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 2

Sample Output

14

HINT

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\n",sum);
 82 }
 83 
 84 void output()
 85 {
 86     for(int i=1;i<=len;i+=2)
 87     {
 88         printf("%d -> %d = %d , %d \n",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 }
View Code

 

  建图超机智的,我想不到啊!!

 

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\n",a[0][0]);
74     }
75     else printf("-1\n");
76     return 0;
77 }
View Code

【对偶版本,不需要初始化,快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\n",-a[0][0]);
76     }
77     else printf("-1\n");
78     return 0;
79 }
View Code

对偶就是i和j反,系数正负全反。。。

posted @ 2017-04-25 20:28 konjak魔芋 阅读(...) 评论(...) 编辑 收藏