题目大意
有n种植物,每种植物生长需要
n≤50
题解
这题很难。首先假设有两种超级植物S,T,表示S要一开始长,
⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪ys+λxixtyixi+dixi≥xt≥ys≥yi≥xi≥yi≥yj(j要在i前)
目标函数是
minimize{∑di×ci}
接下来需要考虑一些经典的对偶模型。对于最大循环费用流,其线性规划模型是
⎧⎩⎨⎪⎪fi,j∑jfi,j≥bi,j=∑jfj,imaximize{∑fi,j×costi,j}
这个东西的对偶,就是
vi,j+ϕi−ϕj≥costi,jminimize{∑vi,j×bi,j}
可以发现这个对偶问题貌似能套在原问题上。
比如对于这条式子
yi−xi+di≥ti
是可以直接套的,这相当于在循环流中连上一条xi→yi的流量为ci费用为ti的边。
那么对于类似xi−yj≥0这样的限制,我们只能强行给他加上一个变量p来凑
最后的问题是,给定图G,如何求一个最大循环流。
最大循环流
这个问题等价于我们用若干个环,使得其覆盖的权值和最大。
一个点在环上,等价于其入度=出度。
那么我们一开始先贪心的把所有权值为正数的边都选上,同时修改两端的度数。对于一条负边权(u,v,f,c),相当于我们可以以c的代价使得
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1005;
typedef long long ll;
class network
{
public:
struct node
{
ll to,next,flow,cost;
node(void){}
node(int a,int b,ll c,ll d) : to(a),next(b),flow(c),cost(d){}
}e[maxn * 100];
ll deg[maxn];
int final[maxn],ed[maxn][4],n,tot,s,t,cnt;
void set(int siz)
{
n = siz,s = n,t = n + 1;
for(int i = 0;i <= t;i ++) final[i] = deg[i] = 0;
tot = 1;
cnt = 0;
}
void link(int u,int v,ll f,ll c)
{
e[++ tot] = node(v,final[u],f,c),final[u] = tot;
e[++ tot] = node(u,final[v],0,-c),final[v] = tot;
}
void push(int u,int v,int f,int c)
{
ed[++ cnt][0] = u,ed[cnt][1] = v,ed[cnt][2] = f,ed[cnt][3] = c;
}
ll maxflow()
{
static ll dis[maxn];
static int pr[maxn];
static bool in[maxn];
ll ret = 0;
for(;;)
{
for(int i = 0;i <= t;i ++) dis[i] = (1ll << 60),in[i] = 0;
dis[s] = 0;
static int que[maxn * 100];
que[1] = s;
in[s] = 1;
for(int fi = 1,en = 1;fi <= en;fi ++)
{
int u = que[fi];
for(int i = final[u];i;i = e[i].next)
if (e[i].flow > 0 && dis[e[i].to] > dis[u] + e[i].cost)
{
dis[e[i].to] = dis[u] + e[i].cost;
pr[e[i].to] = i;
if (!in[e[i].to])
{
in[e[i].to] = 1,que[++ en] = e[i].to;
}
}
in[u] = 0;
}
if (dis[t] == (1ll << 60)) break;
ll fl = (1ll << 60);
for(int i = t;i != s;i = e[pr[i] ^ 1].to)
fl = min(fl,e[pr[i]].flow);
ret += fl * dis[t];
for(int i = t;i != s;i = e[pr[i] ^ 1].to)
e[pr[i]].flow -= fl,e[pr[i] ^ 1].flow += fl;
}
return ret;
}
ll calc()
{
ll sum = 0;
for(int i = 1;i <= cnt;i ++)
{
ll u = ed[i][0],v = ed[i][1],f = ed[i][2],c = ed[i][3];
if (c < 0)
link(u,v,f,-c); else
{
sum += f * c;
deg[u] += f,deg[v] -= f;
link(v,u,f,c);
}
}
for(int i = 0;i < n;i ++)
if (deg[i] < 0) link(s,i,-deg[i],0); else link(i,t,deg[i],0);
return sum - maxflow();
}
}flow;
class Farmville
{
public:
int minTime(vector<string> s, vector<int> t, vector<int> c,int budget)
{
int l = 0,r = 100000,tmp,n = t.size();
for(int mid;l <= r;)
{
mid = l + r >> 1;
flow.set(n * 2 + 2);
int ys = n * 2,xt = n * 2 + 1;
for(int i = 0;i < n;i ++)
{
flow.push(ys,i << 1,1 << 30,0),flow.push(i << 1 | 1,xt,1 << 30,0);
flow.push(i << 1,i << 1 | 1,1 << 30,0),flow.push(i << 1,i << 1 | 1,c[i],t[i]);
}
for(int i = 0;i < n;i ++)
for(int j = 0;j < n;j ++)
if (s[i][j] == '1') flow.push(j << 1 | 1,i << 1,1 << 30,0);
flow.push(xt,ys,1 << 30,-mid);
if (flow.calc() > budget) l = mid + 1; else
tmp = mid,r = mid - 1;
}
return tmp;
}
};