UPD:好吧 我绝望的发现这些乱七八糟的本质上全是一样的 此文已废 2017.06.07
这个题目啊
我们用样例说话吧 列出来的式子是这样的
对偶一下
By the way 这个的解 是 3 1 2
看到这个东西直接无脑simplex啊 管他是不是全幺模
然后就过了
#include<cstdio>
#include<cstdlib>
#include<cmath>
#define eps 1e-10
#define inf 1e20;
using namespace std;
inline int dcmp(double a,double b){
if (fabs(a-b)<eps) return 0;
if (a<b) return -1;
return 1;
}
int n,m;
double Ans;
double a[1005][10005];
int next[10005];
inline void PIVOT(int l,int e){
for (int i=0;i<=n;i++)
if (i!=e)
a[l][i]/=a[l][e];
a[l][e]=1/a[l][e];
int last=-1;
for (int i=0;i<=n;i++)
if (a[l][i])
next[i]=last,last=i;
for (int i=0;i<=m;i++){
if (i==l || a[i][e]==0) continue;
for (int j=last;j!=-1;j=next[j]){
if (j==e) continue;
a[i][j]-=a[i][e]*a[l][j];
}
a[i][e]=-a[i][e]*a[l][e];
}
}
inline double Simplex(){
int l,e;
double minimum;
while (1){
for (e=1;e<=n && a[0][e]<=0;e++);
if (e==n+1) return -a[0][0];
minimum=inf;
for (int i=1;i<=m;i++)
if (a[i][e]>0 && dcmp(minimum,a[i][0]/a[i][e])>0)
minimum=a[l=i][0]/a[i][e];
PIVOT(l,e);
}
}
int main(){
int l,r,w;
freopen("defend.in","r",stdin);
freopen("defend.out","w",stdout);
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++) scanf("%lf",&a[i][0]);
for (int i=1;i<=n;i++){
scanf("%d%d%lf",&l,&r,&a[0][i]);
for (int j=l;j<=r;j++) a[j][i]=1;
}
Ans=Simplex();
printf("%.0lf\n",Ans);
return 0;
}
可是考场上simplex板子没背熟怎么办啊
我们可以上费用流!
差分费用流是什么呢
我们看这个
红色表示容量 绿色表示费用
每个不等式弄成一个点
红色出边代表式子的限制
绿色的边流一个流量会发现就是一个变量++ 对一串不等式有贡献
这就是个最大费用可行流啊
然后激动的建完图后发现不会搞有正环的东西啊
我们这么搞 建个超级源汇 把正边强制流满 对原图流量不平衡了
然后在新图上跑最小费用最大流 这就是把超级源汇多出来的不平衡流量全部退流 同时是费用降低的最少
建图是不是很棒 然后这个题费用流狗带了 zkw都救不了 只有70分
UPD 17/02/14
这个建图可以直接由最初的LP对偶而来
具体我另开了一篇文:http://blog.csdn.net/u014609452/article/details/55101021
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
struct edge{
int u,v,f,w;
int next;
}G[N<<1];
int head[N],inum=1;
inline void add(int u,int v,int w,int f,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w,int f){
add(u,v,w,f,++inum); add(v,u,-w,0,++inum);
}
int S,T;
int pre[N],dis[N],ins[N];
int Q[1000005],l,r;
#define V G[p].v
ll Mincost;
int icnt=0;
inline bool SPFA(){
for (int i=1;i<=T;i++) dis[i]=1<<30,pre[i]=0,ins[i]=0;
l=r=-1; dis[S]=0; Q[++r]=S; ins[S]=1;
while (l!=r){
int u=Q[++l]; ins[u]=0;
for (int p=head[u];p;p=G[p].next)
if (G[p].f && dis[V]>dis[u]+G[p].w){
dis[V]=dis[u]+G[p].w; pre[V]=p;
if (!ins[V]) Q[++r]=V,ins[V]=1;
}
}
if (dis[T]==(1<<30)) return 0;
int minv=1<<30;
for (int p=pre[T];p;p=pre[G[p].u])
minv=min(minv,G[p].f);
Mincost+=(ll)minv*dis[T];
for (int p=pre[T];p;p=pre[G[p].u])
G[p].f-=minv,G[p^1].f+=minv;
return 1;
}
int n,m; ll Ans;
int deg[N];
int main(){
int iu,iv,iw,maxw=0;
freopen("defend.in","r",stdin);
freopen("defend.out","w",stdout);
read(n); read(m); S=n+1+1; T=n+1+2;
for (int i=1;i<=n;i++)
read(iw),link(i,i+1,0,iw),maxw=max(maxw,iw);
link(n+1,1,0,1<<30);
for (int i=1;i<=m;i++){
read(iu); read(iv); read(iw);
link(iu,iv+1,iw,maxw); deg[iu]+=maxw,deg[iv+1]-=maxw;
Ans+=(ll)maxw*iw;
}
for (int i=1;i<=n+1;i++)
if (deg[i]>0)
link(S,i,0,deg[i]);
else if (deg[i]<0)
link(i,T,0,-deg[i]);
while (SPFA());
printf("%lld\n",Ans-Mincost);
return 0;
}
换一种建图方式 辅助变量是什么呢
我们添加辅助变量把不等式变为等式
一通差分
仔细观查 可以得到每个变量在其中出现一正一负 然后可以联想到流量平衡
将每个不等式看做一个点 每个变量看成一条边 等式右边的值是超级源汇提供这个点的流量
就是每个变量从为正的点连为负的点 有费用
超级源向右边为正的点连边 为容量
超级汇向右边为负的点连边 绝对值为容量
具体建图我画不出来 这个idea是看BYVOID神犇关于employee的题解:https://www.byvoid.com/blog/noi-2008-employee/#more-916
这个费用流跑的还是不行 拷了个zkw模板就过了
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
struct edge{
int u,v,f,w;
int next;
}G[N<<1];
int head[N],inum=1;
inline void add(int u,int v,int w,int f,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w,int f){
add(u,v,w,f,++inum); add(v,u,-w,0,++inum);
}
int S,T;
int pre[N],dis[N],ins[N];
int Q[1000005],l,r;
#define V G[p].v
ll Maxcost;
int icnt=0;
inline bool SPFA(){
for (int i=1;i<=T;i++) dis[i]=-1<<30,pre[i]=0,ins[i]=0;
l=r=-1; dis[S]=0; Q[++r]=S; ins[S]=1;
while (l!=r){
int u=Q[++l]; ins[u]=0;
for (int p=head[u];p;p=G[p].next)
if (G[p].f && dis[V]<dis[u]+G[p].w){
dis[V]=dis[u]+G[p].w; pre[V]=p;
if (!ins[V]) Q[++r]=V,ins[V]=1;
}
}
if (dis[T]==(-1<<30)) return 0;
int minv=1<<30;
for (int p=pre[T];p;p=pre[G[p].u])
minv=min(minv,G[p].f);
Maxcost+=(ll)minv*dis[T];
for (int p=pre[T];p;p=pre[G[p].u])
G[p].f-=minv,G[p^1].f+=minv;
return 1;
}
int n,m;;
int val[N];
int main(){
int iu,iv,iw,maxw=0;
freopen("defend.in","r",stdin);
freopen("defend.out","w",stdout);
read(n); read(m); S=n+1+1; T=n+1+2;
for (int i=1;i<=n;i++) read(val[i]);
for (int i=1;i<=m;i++){
read(iu); read(iv); read(iw);
link(iu,iv+1,iw,1<<30);
}
for (int i=1;i<=n;i++)
link(i,i+1,0,1<<30);
for (int i=1;i<=n+1;i++)
if (val[i]-val[i-1]>0)
link(S,i,0,val[i]-val[i-1]);
else
link(i,T,0,val[i-1]-val[i]);
while (SPFA());
printf("%lld\n",Maxcost);
return 0;
}
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
#define MAXN 55555
#define MAXM 55555
#define INF 100000007
using namespace std;
struct EDGE{
int cost, cap, v;
int next, re;
}edge[MAXM];
int head[MAXN], e;
int vis[MAXN], d[MAXN];
ll ans, cost;
int src, des, n;
void init(){
memset(head, -1, sizeof(head));
e = 0;
ans = cost = 0;
}
void add(int u, int v, int cap, int cost) {
edge[e].v = v; edge[e].cap = cap; edge[e].cost = cost; edge[e].re = e + 1; edge[e].next = head[u]; head[u] = e++;
edge[e].v = u; edge[e].cap = 0; edge[e].cost = -cost; edge[e].re = e - 1; edge[e].next = head[v]; head[v] = e++;
}
int aug(int u, int f){
if(u == des){
ans += (ll)cost * f;
return f;
}
vis[u] = 1;
int tmp = f;
for(int i = head[u]; i != -1; i = edge[i].next)
if(edge[i].cap && !edge[i].cost && !vis[edge[i].v]){
int delta = aug(edge[i].v, tmp < edge[i].cap ? tmp : edge[i].cap);
edge[i].cap -= delta;
edge[edge[i].re].cap += delta;
tmp -= delta;
if(!tmp) return f;
}
return f - tmp;
}
bool modlabel(){
for(int i = 0; i <= n; i++) d[i] = INF;
d[des] = 0;
deque<int>Q;
Q.push_back(des);
while(!Q.empty()){
int u = Q.front(), tmp;
Q.pop_front();
for(int i = head[u]; i != -1; i = edge[i].next)
if(edge[edge[i].re].cap && (tmp = d[u] - edge[i].cost) < d[edge[i].v])
(d[edge[i].v] = tmp) <= d[Q.empty() ? src : Q.front()] ? Q.push_front(edge[i].v) : Q.push_back(edge[i].v);
}
for(int u = 1; u <= n; u++)
for(int i = head[u]; i != -1; i = edge[i].next)
edge[i].cost += d[edge[i].v] - d[u];
cost += d[src];
return d[src] < INF;
}
void costflow(){
while(modlabel()){
do{
memset(vis, 0, sizeof(vis));
}while(aug(src, INF));
}
}
int in,im;;
int val[100005];
int main(){
int iu,iv,iw,maxw=0;
freopen("defend.in","r",stdin);
freopen("defend.out","w",stdout);
read(in); read(im); src=in+1+1; des=in+1+2; n=des;
init();
for (int i=1;i<=in;i++) read(val[i]);
for (int i=1;i<=im;i++){
read(iu); read(iv); read(iw);
add(iu,iv+1,1<<30,-iw);
}
for (int i=1;i<=in;i++)
add(i,i+1,1<<30,0);
for (int i=1;i<=in+1;i++)
if (val[i]-val[i-1]>0)
add(src,i,val[i]-val[i-1],0);
else
add(i,des,val[i-1]-val[i],0);
costflow();
printf("%lld\n",-ans);
return 0;
}