线性规划:
给出若干个不等式,再给出个函数G(),求出G()的极值
例如①x2+x3>=1;②x1+x2+x3+x4+x5>=4;③x3+x4+x5>=2
G() = x1+5*x2+6*x3+3*x4+4*x5,求G()的最小值
部分的线性规划问题可以用网络流来解决
如果原不等式系数矩阵每一列上不为0的相同且连续,那么就可以
先看上面那个例子的系数矩阵:
1 5 6 3 4(求min)
1 1 1(>=)
1 1 1 1 1 4
1 1 1 2
虽然这个系数矩阵满足上面的要求,但它是行连续的,仅这个样例满足而已
可以把这个矩阵翻转90°:
1 4 2(求max)
1 1(<=)
1 1 5
1 1 1 6
1 1 3
1 1 4
一定满足要求!它对应的新多项式为①y2<=1;②y1+y2<=5;③y1+y2+y3<=6;④y2+y3<=3;⑤y2+y3<=4(没意义)
G() = y1+4*y2+2*y3,求G()的最大值
到这里问题就变得可解了,下一步:将原不等式加入松弛变量后进行差分
①y2+y4=1;②y1+y2+y5=5;③y1+y2+y3+y6=6;④y2+y3+y7=3;⑤0=0
然后拿所有式子减去上一个式子:
①y2+y4=1;②y1+y5-y4=4;③y3+y6-y5=1;④y7-y1-y6=-3;⑤-y2-y3-y7=-3
因为原先系数矩阵每一列上不为0的相同且连续,所以在这里每个变量一定只出现2次,一次正一次负,相当于网络流流量守恒,所以可以将每个式子当成一个点,具体建边如下:
①如果第i个等式常数C为正,那么从源点连一条容量为C,费用为0的边,常数C为负则连一条容量为|C|,费用为0的边到汇点
②对于每个变量yi,从它系数为正的式子向系数为负的式子连一条容量为inf,费用为G()里系数的边
这就成了单纯型的网络流,不需要满流求最大费用即可
题解:其实已经在上面了,样例就是例子
http://www.lydsy.com/JudgeOnline/problem.php?id=3112
单纯型可以转成最大费用最大流,将所有与源点直接相连的点再连一条一模一样的边到汇点就好了
但是复杂度比较高,常数大,而且难写,这里有个更简单的方法,只要将对偶的矩阵代入即可求得!
因为篇幅太长,这里就引用一篇文章吧:http://www.cnblogs.com/ScratchingBear/p/5634692.html
还有https://wenku.baidu.com/view/367ab2292f60ddccda38a033.html
a[i][j]:
1 4 2
1 1
5 1 1
6 1 1 1
3 1 1
4 1 1
#include<stdio.h>
#define inf 2147483647
int n, m, a[1010][10010], net[10010];
void Pivot(int l, int e)
{
int i, j, last;
last = -1;
for(i=0;i<=m;i++)
{
if(a[l][i])
{
net[i] = last;
last = i;
}
}
for(i=0;i<=n;i++)
{
if(a[i][e]==0 || i==l)
continue;
for(j=last;j!=-1;j=net[j])
{
if(j==e)
continue;
a[i][j] -= a[i][e]*a[l][j];
}
a[i][e] = -a[i][e];
}
}
int SimpleX()
{
int now, temp, k, i;
while(1)
{
now = 0;
for(i=1;i<=m;i++)
{
if(a[0][i]>0)
{
now=i;
break;
}
}
if(now==0)
return -a[0][0];
k = inf;
for(i=1;i<=n;i++)
{
if(a[i][now]>0 && a[i][0]<k)
{
temp = i;
k = a[i][0];
}
}
Pivot(temp, now);
}
}
int main(void)
{
int ans;
int x, y, j, i;
scanf("%d%d", &n, &m);
for(i=1;i<=n;i++)
scanf("%d", &a[i][0]);
for(i=1;i<=m;i++)
{
scanf("%d%d%d", &x, &y, &a[0][i]);
for(j=x;j<=y;j++)
a[j][i] = 1;
}
ans = SimpleX();
printf("%d\n", ans);
return 0;
}