1. 程式人生 > >【BZOJ 1061】 1061: [Noi2008]志願者招募 (線性規劃與網路流)**

【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題都沒有涉及到線性規劃的轉化的。。

  這道的確是經典題,但是轉化挺難的。。

  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反,係數正負全反。。。