【BZOJ】1061: [Noi2008]誌願者招募
阿新 • • 發佈:2018-06-18
真的 inline LV ace 誌願者 algo bzoj div 誌願者招募
\(x_1,x_2,x_3 >= 0\)
顯然,標準型要求我們這些式子是小於號並且z要取max
好吧,反號?
不過我們有個很神奇的原理叫對偶原理
(我是真的不知道為啥……)
\(0 + x_2 + x_3 + x_5 = 5\)
\(0 + 0 + x_3 + x_6 = 2\)
我們3個方程組,6個元,是消不出來的,我們這是一些作為基變量,剩下的非基變量都設成0,那樣的話一定是單純形上的一個頂點
題解
可能是世界上最裸的一個單純形
(話說全幺模矩陣是啥我到現在都不知道)
假裝我們已經看過了算導,或者xxx的論文,知道了單純形是怎麽實現的
扔一個blog走掉。。https://www.cnblogs.com/ECJTUACM-873284962/p/7097864.html
那麽我們根據題意可以列出這樣的方程
\(x_i\)表示第\(i\)類誌願者招募的個數
根據題目可列線性規劃的式子
以樣例為例
\(z = min 2x_1 + 5x_2 + 2x_3\)
\(x_1 + 0 + 0 >= 2\)
\(x_1 + x_2 + 0 >= 3\)
\(0 + x_2 + x_3 >= 4\)
\(x_1,x_2,x_3 >= 0\)
顯然,標準型要求我們這些式子是小於號並且z要取max
好吧,反號?
不過我們有個很神奇的原理叫對偶原理
(我是真的不知道為啥……)
也就是
\(min c^T X\)
\(Ax = b\)
等價於
\(max b^T X\)
\(A^TX = c\)
好吧,這是我們喜歡的形式啊
然後我們的方程就可以寫成這個樣子
\(z = max 2x_1 + 3x_2 + 4x_3\)
\(x_1 + x_2 + 0 <= 2\)
\(0 + x_2 + x_3 <= 5\)
\(0 + 0 + x_3 <= 2\)
我們把這個方程轉換成松弛型(也就是全是等於號)
\(x_1 + x_2 + 0 + x_4 = 2\)
\(0 + x_2 + x_3 + x_5 = 5\)
\(0 + 0 + x_3 + x_6 = 2\)
我們3個方程組,6個元,是消不出來的,我們這是一些作為基變量,剩下的非基變量都設成0,那樣的話一定是單純形上的一個頂點
這是一個\(m * (n + m)\)的矩陣,有點大
我們在處理的時候,初始設定所有的\(x_4,x_5,x_6\)作為基變量
每一個方程就是一個關於基變量的等式,我們找到一個替入變量,找到能使替入變量值最大的方程組的等式,將替入變量的位置當做替出變量的位置,矩陣就是\(nm\)的了
代碼
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <cmath>
#define enter putchar(‘\n‘)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define eps 1e-7
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < ‘0‘ || c > ‘9‘) {
if(c == ‘-‘) f = -1;
c = getchar();
}
while(c >= ‘0‘ && c <= ‘9‘) {
res = res * 10 + c - ‘0‘;
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar(‘-‘);x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar(‘0‘ + x % 10);
}
const int MAXN = 1005;
const int MAXM = 10005;
int N,M;
db b[MAXM],c[MAXN],a[MAXM][MAXN],ans;
void pivot(int id,int p) {
b[id] /= a[id][p];
for(int j = 1 ; j <= N ; ++j) {
if(j != p) a[id][j] /= a[id][p];
}
a[id][p] = 1 / a[id][p];
for(int i = 1 ; i <= M ; ++i) {
if(i != id) {
if(fabs(a[i][p]) < eps) continue;
for(int j = 1 ; j <= N ; ++j) {
if(j != p) a[i][j] -= a[i][p] * a[id][j];
}
b[i] -= a[i][p] * b[id];a[i][p] = -a[i][p] * a[id][p];
}
}
for(int j = 1 ; j <= N ; ++j) {
if(j != p) c[j] -= c[p] * a[id][j];
}
ans += c[p] * b[id];c[p] = -c[p] * a[id][p];
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) scanf("%lf",&c[i]);
int s,t;
for(int i = 1 ; i <= M ; ++i) {
scanf("%d %d %lf",&s,&t,&b[i]);
for(int j = s ; j <= t ; ++j) {
a[i][j] = 1.0;
}
}
}
void Solve() {
while(1) {
db t = -1;int p = 0;
for(int i = 1 ; i <= N ; ++i) {
if(c[i] > t) {
t = c[i];p = i;
}
}
if(t <= 0) {printf("%.0lf\n",ans);return;}
t = 0x5fffffff;int id = 0;
for(int j = 1 ;j <= M ; ++j) {
if(a[j][p] > 0 && b[j] / a[j][p] < t) {
t = b[j] / a[j][p];
id = j;
}
}
pivot(id,p);
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}
【BZOJ】1061: [Noi2008]誌願者招募