题目链接
题解
除了数据范围和修车一样
对于没人没个要求拆点间图
增光一条后更改下次增广费用
然后要返向啊,不然就T了,好坑啊
然后在西校写代码在东校调试,代码格式好鬼畜啊
代码
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
inline int read() {
int x = 0;
char c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c <= '9' && c >= '0')x = x * 10 + c - '0',c = getchar();
return x ;
}
const int maxn = 100007 ;
struct Node {
int next,u,flow,v,cost;
}edge[maxn << 2 + 1]; int num = 1,head[maxn];
inline void add_edge(int u,int v,int flow,int cost) {
edge[++ num].v = v;edge[num].u = u;edge[num].cost = cost,edge[num].flow = flow,edge[num].next = head[u];head[u] = num;
}
inline void Add(int u,int v,int flow,int cost) {add_edge(u,v,flow,cost);add_edge(v,u,0,-cost); }
int c[maxn],p[105][105],dis[maxn],pre[maxn];bool vis[maxn];
int que[maxn];
int n,m,tot = 0,S,T,ans;
bool spfa() {
for(int i = 0;i <= T;++ i) vis[i] = 0,dis[i] = 0x3f3f3f3f;
dis[S] = 0;vis[S] = 1;
int l = 0,r = 1;
que[l] = S;
while(l < r) {
int u = que[l ++];if(l == T) l = 0;
for(int i = head[u];i;i = edge[i].next) {
int v = edge[i].v;
if(edge[i].flow > 0 && dis[v] > dis[u] + edge[i].cost) {
pre[v] = i;
dis[v] = dis[u] + edge[i].cost;
if(!vis[v]){que[r ++] = v,vis[v] = 1;if(r == T)r = 0;}
}
}
vis[u] = 0;
}
if(dis[T] == 0x3f3f3f3f) return false;
else return true;
}
void MCMF() {
while(spfa()) {
int MIN = 0x7fffffff,y,a,b;
for(int i = pre[T];i;i = pre[edge[i].u])
MIN = std::min(MIN,edge[i].flow);
for(int i = pre[T];i;i = pre[edge[i].u])
edge[i].flow -= MIN ,edge[i ^ 1].flow += MIN,ans += edge[i].cost * MIN;
int x = edge[pre[T]].u;
Add(x + 1,T,1,0);
for(int i = 1;i <= n;++ i) {
Add(m * tot + i,x + 1,1,p[i][x / tot + 1] * (x % tot + 1));
}
}
}
int main() {
n = read(),m = read();
S = 0;T = 100001;
for(int i = 1;i <= n;++ i) c[i] = read(), tot += c[i];
for(int i = 1;i <= n;++ i) {
Add(S,i + tot * m,c[i],0);
for(int j = 1;j <= m;++ j) {
p[i][j] = read();
Add(i + tot * m,(j - 1) * tot + 1,1,p[i][j]);
}
}
for(int i = 1;i <= m;++ i) Add((i - 1) * tot + 1,T,1,0);
MCMF();
printf("%d
",ans);
return 0;
}
/*
*/