书上写的是UVa 12011, 实际上是 12264

参考了https://blog.csdn.net/xl2015190026/article/details/51902823

这道题就是求出一种最优的移动士兵的方式, 使得与敌方相邻的阵营中最少的士兵最多

因为只能在我方的阵营中移动士兵, 所以建模的时候不用加入地方阵营的点。

首先因为士兵只能移动一次, 所以把点拆成两个点, 入点和出点。

设阵营士兵的人数为k[i]

那么源点到入点连一条弧, 容量为k[i], 然后入点和出点再连

一条弧, 容量为k[i]

然后因为士兵可以移动, 所以相邻的阵营之间, 如i与j, 那么i的入点

和j的出点连一条弧, 容量为最多可以给的士兵的数量, 可以设为k[i]

实际上不可能给k[i]那么多个,因为每个阵营少留下一个人。

但是容量多了没事, 反正多了也流不过来。这里设为无穷大效果也是一样的

这类弧表示相邻的阵营之间可以有士兵移动

然后现在要从出点到汇点连一条弧, 这条弧的流量表示最终这个阵营的人数

中间入点和出点的弧有流量, 就是表示士兵是在原来的阵营还是去其他阵营

流到最后每个阵营流出去的流量就是最后这个阵营的人数。

然后容量为多少呢?

首先要使最少的尽量多, 那么如果这个阵营不与敌方阵营相邻, 那么也就是说

这个阵营只要满足人数大于1就可以了。那么显然, 为了给那些与敌方阵营相邻

的阵营更多的人数, 那么这类阵营的人数干脆就为1了。

所以容量为1。如果与地方阵营相邻, 要使最少的最多, 那么在肯定是平均分最好。

那么这个平均的值是不确定的, 所以我们要二分

也就是说二分答案, 二分的这个值就是弧的容量。

最后如果满载的话说明满足条件, 那么就符合。

#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
using namespace std; const int MAXN = 212;
struct Edge{ int from, to, cap, flow; };
vector<Edge> edges;
vector<int> g[MAXN];
int cur[MAXN], h[MAXN], k[MAXN], f[MAXN];
int n, m, s, t;
char map[MAXN][MAXN]; void AddEdge(int from, int to, int cap)
{
edges.push_back(Edge{from, to, cap, 0});
edges.push_back(Edge{to, from, 0, 0});
g[from].push_back(edges.size() - 2);
g[to].push_back(edges.size() - 1);
} bool bfs()
{
queue<int> q;
q.push(s);
memset(h, 0, sizeof(h));
h[s] = 1; while(!q.empty())
{
int x = q.front(); q.pop();
REP(i, 0, g[x].size())
{
Edge& e = edges[g[x][i]];
if(e.cap > e.flow && !h[e.to])
{
h[e.to] = h[x] + 1;
q.push(e.to);
}
}
} return h[t];
} int dfs(int x, int a)
{
if(x == t || a == 0) return a;
int flow = 0, f;
for(int& i = cur[x]; i < g[x].size(); i++)
{
Edge& e = edges[g[x][i]];
if(h[x] + 1 == h[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
{
e.flow += f;
edges[g[x][i] ^ 1].flow -= f;
flow += f;
if((a -= f) == 0) break;
}
}
return flow;
} int maxflow()
{
int flow = 0;
while(bfs())
{
memset(cur, 0, sizeof(cur));
flow += dfs(s, 1e9);
}
return flow;
} int make_edges(int cap)
{
edges.clear();
REP(i, 0, MAXN) g[i].clear();
memset(f, false, sizeof(f)); REP(i, 0, n)
{
if(!k[i]) continue;
AddEdge(s, i, k[i]);
AddEdge(i, i + n, k[i]);
REP(j, 0, n)
if(map[i][j] == 'Y')
{
if(k[j]) AddEdge(i, j + n, k[i]);
else f[i] = true;
}
} int ret = 0;
REP(i, 0, n)
if(k[i])
{
if(f[i]) AddEdge(i + n, t, cap), ret += cap;
else AddEdge(i + n, t, 1), ret++;
}
return ret;
} int main()
{
int T;
scanf("%d", &T); while(T--)
{
scanf("%d", &n);
REP(i, 0, n) scanf("%d", &k[i]);
REP(i, 0, n) scanf("%s", map[i]);
s = 2 * n; t = s + 1; int l = 0, r = MAXN * MAXN;
while(l + 1 < r)
{
int mid = (l + r) >> 1;
if(make_edges(mid) == maxflow()) l = mid;
else r = mid;
}
printf("%d\n", l);
} return 0;
}

紫书 习题 11-10 UVa 12264 (二分答案+最大流)的更多相关文章

  1. 紫书 习题8-14 UVa 1616(二分+小数化分数+精度)

    参考了https://www.cnblogs.com/dwtfukgv/p/5645446.html (1)直接二分答案.说实话我没有想到, 一开始以为是贪心, 以某种策略能得到最优解. 但是想了很久 ...

  2. 紫书 习题 11-9 UVa 12549 (二分图最小点覆盖)

    用到了二分图的一些性质, 最大匹配数=最小点覆盖 貌似在白书上有讲 还不是很懂, 自己看着别人的博客用网络流写了一遍 反正以后学白书应该会系统学二分图的,紫书上没讲深. 目前就这样吧. #includ ...

  3. 紫书 习题 11-8 UVa 1663 (最大流求二分图最大基数匹配)

    很奇怪, 看到网上用的都是匈牙利算法求最大基数匹配 紫书上压根没讲这个算法, 而是用最大流求的. 难道是因为第一个人用匈牙利算法然后其他所有的博客都是看这个博客的吗? 很有可能-- 回归正题. 题目中 ...

  4. 紫书 习题8-12 UVa 1153(贪心)

    本来以为这道题是考不相交区间, 结果还专门复习了一遍前面写的, 然后发现这道题的区间是不是 固定的, 是在一个范围内"滑动的", 只要右端点不超过截止时间就ok. 然后我就先考虑有 ...

  5. 紫书 习题8-7 UVa 11925(构造法, 不需逆向)

    这道题的意思紫书上是错误的-- 难怪一开始我非常奇怪为什么第二个样例输出的是2, 按照紫书上的意思应该是22 然后就不管了,先写, 然后就WA了. 然后看了https://blog.csdn.net/ ...

  6. Risk UVA - 12264 拆点法+最大流+二分 最少流量的节点流量尽量多。

    /** 题目:Risk UVA - 12264 链接:https://vjudge.net/problem/UVA-12264 题意:给n个点的无权无向图(n<=100),每个点有一个非负数ai ...

  7. BZOJ 1738: [Usaco2005 mar]Ombrophobic Bovines 发抖的牛( floyd + 二分答案 + 最大流 )

    一道水题WA了这么多次真是.... 统考终于完 ( 挂 ) 了...可以好好写题了... 先floyd跑出各个点的最短路 , 然后二分答案 m , 再建图. 每个 farm 拆成一个 cow 点和一个 ...

  8. Gym - 101908G 二分答案+最大流

    After the end of the truck drivers' strike, you and the rest of Nlogônia logistics specialists now h ...

  9. BZOJ 1570: [JSOI2008]Blue Mary的旅行( 二分答案 + 最大流 )

    二分答案, 然后对于答案m, 把地点分成m层, 对于边(u, v), 第x层的u -> 第x+1层的v 连边. 然后第x层的u -> 第x+1层的u连边(+oo), S->第一层的1 ...

随机推荐

  1. Android 7.0 Gallery图库源码分析3 - 数据加载及显示流程

    前面分析Gallery启动流程时,说了传给DataManager的data的key是AlbumSetPage.KEY_MEDIA_PATH,value值,是”/combo/{/local/all,/p ...

  2. HDU 1465 不容易系列之一( 错排水题 )

    链接:传送门 思路:错排模板题,水题是非常浪费时间的 /************************************************************************ ...

  3. 线段树合并(【POI2011】ROT-Tree Rotations)

    线段树合并([POI2011]ROT-Tree Rotations) 题意 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有nn个叶子节点,满足这些权值为1-n1-n的一个 ...

  4. php中mysqli 处理查询结果集总结

    在PHP开发中,我们经常会与数据库打交道.我们都知道,一般的数据处理操作流程为 接收表单数据 数据入库 //连接数据库 $link = mysqli_connect("my_host&quo ...

  5. 小学生都能学会的python(文件操作)

    小学生都能学会的python(文件操作) 1. open("文件路径", mode="模式", encoding="编码") 文件的路径: ...

  6. java中BufferedReader 有什么用

    这个类就是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了或者你flush的时候,再读入内存,就是为了提供读的效率而设计的. BufferedReader buffer ...

  7. codevs——T1814 最长链

    http://codevs.cn/problem/1814/  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 De ...

  8. error: could not install *smartsocket* listener: Address already in use 下午8:49 ADB server didn't ACK 下午8:49 * failed to start daemon * 下午8:49 error: cannot connect to daemon

    在终端输入adb命令,出错如下: localhost:work zhangyg$ adb devices List of devices attached adb server version (32 ...

  9. leetcode笔记:Find Median from Data Stream

    一. 题目描写叙述 Median is the middle value in an ordered integer list. If the size of the list is even, th ...

  10. struts2请求过程源代码分析

    struts2请求过程源代码分析 Struts2是Struts社区和WebWork社区的共同成果.我们甚至能够说,Struts2是WebWork的升级版.他採用的正是WebWork的核心,所以.Str ...