ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

ZOJ3229 Shoot the Bullet

2021-05-29 19:51:37  阅读:231  来源: 互联网

标签:Shoot head Bullet int flow ecnt ZOJ3229 include dis


嘟嘟嘟


有源有汇上下界网络流之最大流。


这题建图其实不难,从\(s\)向每一天连容量为\([0, D]\)的边,每一天向对应的女孩连容量为\([L, R]\)的边,每一个女孩向汇点连容量为\([G, INF]\)的边。
然后转换成上下界网络流的图:建立附加源附加汇\(S, T\),计算每一个点的出入度之差后连边。这时候还要从\(t\)到\(s\)连一条\([0, INF]\)的边,形成循环流。
然后从\(S\)到\(T\)跑一边最大流,如果流满。则说明存在可行流,于是切掉\(t\)到\(s\)的边,再从\(s\)到\(t\)跑一边最大流。则答案就是第一次\(s\)到\(t\)的流加上第二次的流。
求第一次\(s\)到\(t\)的流有一个技巧,因为已经连了\(t\)到\(s\)的一条边,所以只要取反向边的流量的相反数即可。


19.04.24更新
在某篇博客上看到,可以不删边,再跑一遍\(s, t\)的最大流,那么答案就是这次的最大流!


然后我因为数组开的过大(才$5e6$)在zoj上段错误了…… ```c++ #include #include #include #include #include #include #include #include #include #include using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define rg register typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 1505; const int maxe = 1e5 + 5; inline ll read() { ll ans = 0; char ch = getchar(), last = ' '; while(!isdigit(ch)) last = ch, ch = getchar(); while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); if(last == '-') ans = -ans; return ans; } inline void write(ll x) { if(x < 0) x = -x, putchar('-'); if(x >= 10) write(x / 10); putchar(x % 10 + '0'); }

int n, m, s, t, S, T;

struct Edge
{
int nxt, from, to, cap, flow;
}e[maxe];
int head[maxn], ecnt = -1;
void addEdge(int x, int y, int w)
{
e[++ecnt] = (Edge){head[x], x, y, w, 0};
head[x] = ecnt;
e[++ecnt] = (Edge){head[y], y, x, 0, 0};
head[y] = ecnt;
}

int dis[maxn];
bool bfs(int s, int t)
{
Mem(dis, 0); dis[s] = 1;
queue q; q.push(s);
while(!q.empty())
{
int now = q.front(); q.pop();
for(int i = head[now], v; i != -1; i = e[i].nxt)
{
if(!dis[v = e[i].to] && e[i].cap > e[i].flow)
{
dis[v] = dis[now] + 1;
q.push(v);
}
}
}
return dis[t];
}
int cur[maxn];
int dfs(int now, int _t, int res)
{
if(now == _t || res == 0) return res;
int flow = 0, f;
for(int& i = cur[now], v; i != -1; i = e[i].nxt)
{
if(dis[v = e[i].to] == dis[now] + 1 && (f = dfs(v, _t, min(res, e[i].cap - e[i].flow))) > 0)
{
e[i].flow += f; e[i ^ 1].flow -= f;
flow += f; res -= f;
if(res == 0) break;
}
}
return flow;
}

int maxflow(int s, int t)
{
int flow = 0;
while(bfs(s, t))
{
memcpy(cur, head, sizeof(head));
flow += dfs(s, t, INF);
}
return flow;
}

int b[maxn][maxn], d[maxn];
void init()
{
Mem(head, -1); ecnt = -1;
Mem(d, 0); Mem(b, 0);
s = 0, t = n + m + 1;
S = t + 1; T = S + 1;
}

int st[maxn];
void print()
{
for(int i = 1; i <= n; ++i)
{
int top = 0;
for(int j = head[i], v; j != -1; j = e[j].nxt)
{
v = e[j].to;
if(v > n && v <= n + m) //别忘了前向星是倒着存边
st[++top] = e[j].flow + b[i][v - n];
}
while(top) write(st[top]), enter, top--;
}
}

int main()
{
while(~scanf("%d%d", &n, &m))
{
init();
for(int i = 1; i <= m; ++i)
{
int x = read();
addEdge(i + n, t, INF - x);
d[i + n] += x; d[t] -= x;
}
for(int i = 1; i <= n; ++i)
{
int C = read(), D = read();
addEdge(s, i, D);
//d[s] += D; d[i] -= D; //最小流量为0,所以不加
for(int j = 1; j <= C; ++j)
{
int id = read() + 1, L = read(), R = read();
b[i][id] = L;
addEdge(i, id + n, R - L);
d[i] += L; d[id + n] -= L;
}
}
int tot = 0;
for(int i = 0; i <= t; ++i)
if(d[i] < 0) addEdge(S, i, -d[i]);
else addEdge(i, T, d[i]), tot += d[i];
addEdge(t, s, INF);
if(maxflow(S, T) < tot) {puts("-1\n"); continue;}
int tp = -e[ecnt].flow; e[ecnt].flow = e[ecnt].cap; // 相当于删去
//上面这一行可以不用,这样答案直接就是maxflow(s, t)
write(tp + maxflow(s, t)), enter;
print(); enter;
}
return 0;
}

标签:Shoot,head,Bullet,int,flow,ecnt,ZOJ3229,include,dis
来源: https://blog.51cto.com/u_15234622/2831213

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有