zoukankan      html  css  js  c++  java
  • 【BZOJ】1061: [Noi2008]志愿者招募

    题解

    可能是世界上最裸的一个单纯形
    (话说全幺模矩阵是啥我到现在都不知道)

    假装我们已经看过了算导,或者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('
    ')
    #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
    ",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();
    }
    
  • 相关阅读:
    图像的仿射变换
    计算机视觉五大技术介绍
    图像处理与Python实现(岳亚伟)笔记五——图像特征提取
    图像处理与Python实现(岳亚伟)笔记四——频域滤波
    图像处理与Python实现(岳亚伟)笔记三——空间滤波
    python 求矩阵的特征值和特征向量
    python + numpy + np.polyfit()(最小二乘多项式拟合曲线)
    Python求定积分+处理can‘t convert expression to float错误
    python reduce() 函数
    python中的sum求和函数
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9195521.html
Copyright © 2011-2022 走看看