【BZOJ3112】防守战线(ZJOI2013)-单纯形法+对偶理论
测试地址(题面在Discuss里):防守战线
做法:这题需要用到线性规划知识中的单纯形法和对偶理论。
观察题目,设每个位置建的塔数为
目标函数:
根据对偶理论,可以将问题转化成关于
目标函数:
这样的话,两个问题的最优解是相等的,且能保证目标函数取最优解时各个变量为整数,所以我们只需用单纯形法解后面的问题即可。
以下是本人代码(TLE70分代码,更高超的卡常数技巧有待学习):
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define inf 1e9
#define eps 1e-8
using namespace std;
int n,m,p[10010];
double a[1010][10010]={0},tmp[10010];
void solve()
{
while(1)
{
int k1,k2;
double Max;
memset(tmp,0,sizeof(tmp));
memset(p,0,sizeof(p));
for(int i=1;i<=m;i++)
if (a[n+1][i]<0)
{
double Min=inf;
for(int j=1;j<=n;j++)
if (a[j][i]>0)
{
double t=a[j][m+1]/a[j][i];
if (Min>t)
{
Min=t;
p[i]=j;
}
}
if (p[i]) tmp[i]=-a[p[i]][m+1]*a[n+1][i]/a[p[i]][i];
}
Max=0.0;
for(int i=1;i<=m;i++)
if (Max<tmp[i])
{
Max=tmp[i];
k2=i;
}
if (fabs(Max)<eps) break;
k1=p[k2];
a[k1][k2]=1.0/a[k1][k2];
for(int i=1;i<=m+1;i++)
if (i!=k2) a[k1][i]*=a[k1][k2];
for(int i=1;i<=n+1;i++)
if (i!=k1)
{
for(int j=1;j<=m+1;j++)
if (j!=k2) a[i][j]-=a[i][k2]*a[k1][j];
}
for(int i=1;i<=n+1;i++)
if (i!=k1) a[i][k2]=-a[i][k2]*a[k1][k2];
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lf",&a[i][m+1]);
for(int i=1;i<=m;i++)
{
int l,r;
double d;
scanf("%d%d%lf",&l,&r,&d);
for(int j=l;j<=r;j++)
a[j][i]=1;
a[n+1][i]=-d;
}
solve();
printf("%.0lf",a[n+1][m+1]);
return 0;
}