题目:My Brute

Seaco是一个漂亮的妹子,喜欢玩一款名叫My Brute的游戏。情人节快到了,starvae和xingxing都想邀请妹子过节,但是妹子只能陪一个啊,于是两个人决定打一架,用男人的方式对决,来一场My Brute吧!

一开始两个人都有n(n<100)只宠物,每个宠物有生命值,伤害值,每次两个人各派出一只宠物,starvae可以任意确定宠物的出场顺序,xingxing不可以。

每局开始starvae先打,hp<=0的一方输。

starvvae的第i个宠物(因为可以换顺序,也就是可能不是第i个出场的)赢vi分,否则减vi分。如果结束时starvae的分数大于0,starvae就赢了。

现在请你求出如果能赢,输出最大分数,和出场顺序和原顺序的相似度(如果最大分数有多种可能的安排方法,选择相似度最大的方法)。不能赢就输出Oh, I lose my dear seaco!

题解:@g3&wy%*¥…sd…#%…

我没做出来。。。因为窝读错题了。。。哭T^T。。。查题解不小心就查到了答案。。。我的英语绝对没救了。。。虽然不知道读对也不知道能不能做出来。。。。。

很好想的是源点连每一个starvae的宠物,流量是1,权值为0,xingxing的每个宠物的连汇点,流量是1,权值为0,两个人的宠物两两相连,能赢权值是v[i],否则是-v[i]。

但是这里求得是最大值,以前也做过求最大值,方法是加边加-w,但这里不行,因为边本来就是有正有负。

所以每次spfa求最短路改为求最长路。记得初始化时是-inf。

还有一个问题是。。。如何保证尽可能原顺序。。。于是有一个比较巧妙的方法,就是把所有v[i]*100,然后把每一个顺序不变的边,权值+1,因为点的个数是100以内的,所以能保证结果正确。。

#include <cstring>
#include <vector>
#include <queue>
#include <cstdio>
using namespace std;
typedef long long ll; const int MAXV = ;
const int INF = <<; struct Edge { int to, cap, cost, rev; };
vector<Edge> G[MAXV];
int dist[MAXV], prv[MAXV], pre[MAXV], in[MAXV];
queue<int> que; void addedge(int from, int to, int cap, int cost) {
G[from].push_back((Edge){to, cap, cost, G[to].size()});
G[to].push_back((Edge){from, , -cost, G[from].size()-});
} int min_cost_max_flow(int s, int t) { //, int f) {
int res = ;
int f = ;
while () { //f > 0) {
for (int i = ; i <= t; ++i) dist[i] = -INF, in[i] = ;
dist[s] = ;
while (!que.empty()) que.pop();
in[s] = ;
que.push(s); while (!que.empty()) {
int u = que.front(); que.pop(); in[u] = ;
for (int i = ; i < G[u].size(); ++i) {
Edge &e = G[u][i];
if (e.cap > && dist[e.to] < dist[u] + e.cost) {
dist[e.to] = dist[u] + e.cost;
prv[e.to] = u;
pre[e.to] = i;
if (in[e.to] == ) {
in[e.to] = ;
que.push(e.to);
}
}
}
} if (dist[t] == -INF) break; //return -1; int d = INF; // d = f;
for (int v = t; v != s; v = prv[v]) {
d = min(d, G[prv[v]][pre[v]].cap);
}
f += d;
res += d * dist[t];
for (int v = t; v != s; v = prv[v]) {
Edge &e = G[prv[v]][pre[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
} const int N = ;
int v[N], h[N], p[N], a[N], b[N]; bool win(int h, int p, int a, int b) { // hp damage
int x = h/b; if (h % b != ) x++;
int y = p/a; if (p % a != ) y++;
return x >= y;
} int main()
{
int n;
while (~scanf("%d", &n) && n) {
for (int i = ; i < n; ++i) scanf("%d", &v[i]);
for (int i = ; i < n; ++i) scanf("%d", &h[i]);
for (int i = ; i < n; ++i) scanf("%d", &p[i]);
for (int i = ; i < n; ++i) scanf("%d", &a[i]);
for (int i = ; i < n; ++i) scanf("%d", &b[i]); int src = , sink = n+n+; for (int i = src; i <= sink; ++i) G[i].clear(); for (int i = ; i < n; ++i) {
for (int j = ; j < n; ++j) {
int tmp = win(h[i], p[j], a[i], b[j]) ? v[i] : -v[i];
tmp *= ; if (i == j) tmp++;
addedge(i+, n+j+, , tmp);
}
} for (int i = ; i < n; ++i) {
addedge(src, i+, , );
addedge(i++n, sink, , );
} int ans = min_cost_max_flow(src, sink); if (ans/ <= ) printf("Oh, I lose my dear seaco!\n");
else printf("%d %.3f%%\n", ans/, ans%/(double)n*); }
return ;
}

既然很明显是二分图

所以可以考虑一下KM解法,建图什么的都一样辣,速度还是一如既往的完爆费用流。。

#include <cstring>
#include <vector>
#include <queue>
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAXN = ;
const int INF = 0x3f3f3f3f; int G[MAXN][MAXN];
int vx[MAXN], vy[MAXN];
bool visx[MAXN], visy[MAXN];
int match[MAXN];
int slack[MAXN]; int N; bool dfs(int x)
{
visx[x] = true; for (int y = ; y < N; ++y) { if (visy[y]) continue; int gap = vx[x] + vy[y] - G[x][y]; if (gap == ) {
visy[y] = true;
if (match[y] == - || dfs( match[y] )) {
match[y] = x;
return true;
}
} else {
slack[y] = min(slack[y], gap);
}
} return false;
} int KM()
{
memset(match, -, sizeof match);
memset(vy, , sizeof vy); for (int i = ; i < N; ++i) {
vx[i] = G[i][];
for (int j = ; j < N; ++j) {
vx[i] = max(vx[i], G[i][j]);
}
} for (int i = ; i < N; ++i) { fill(slack, slack + N, INF); while () {
memset(visx, false, sizeof visx);
memset(visy, false, sizeof visy); if (dfs(i)) break; int d = INF;
for (int j = ; j < N; ++j)
if (!visy[j]) d = min(d, slack[j]); for (int j = ; j < N; ++j) {
if (visx[j]) vx[j] -= d;
if (visy[j]) vy[j] += d;
else slack[j] -= d;
}
}
} int res = ;
for (int i = ; i < N; ++i)
res += G[ match[i] ][i]; return res;
} int v[MAXN], h[MAXN], p[MAXN], a[MAXN], b[MAXN]; bool win(int h, int p, int a, int b) { // hp damage
int x = h/b; if (h % b != ) x++;
int y = p/a; if (p % a != ) y++;
return x >= y;
} int main()
{
int n;
while (~scanf("%d", &n) && n) { N = n;
for (int i = ; i < n; ++i) scanf("%d", &v[i]);
for (int i = ; i < n; ++i) scanf("%d", &h[i]);
for (int i = ; i < n; ++i) scanf("%d", &p[i]);
for (int i = ; i < n; ++i) scanf("%d", &a[i]);
for (int i = ; i < n; ++i) scanf("%d", &b[i]); for (int i = ; i < n; ++i) {
for (int j = ; j < n; ++j) {
int tmp = win(h[i], p[j], a[i], b[j]) ? v[i] : -v[i];
tmp *= ; if (i == j) tmp++;
G[i][j] = tmp;
}
} int ans = KM(); if (ans/ <= ) printf("Oh, I lose my dear seaco!\n");
else printf("%d %.3f%%\n", ans/, ans%/(double)n*); }
return ;
}

hdu3315-My Brute(费用流 or KM算法)的更多相关文章

  1. poj2175费用流消圈算法

    题意:      有n个建筑,每个建筑有ai个人,有m个避难所,每个避难所的容量是bi,ai到bi的费用是|x1-x2|+|y1-y2|+1,然后给你一个n*m的矩阵,表示当前方案,问当前避难方案是否 ...

  2. POJ 2175:Evacuation Plan(费用流消圈算法)***

    http://poj.org/problem?id=2175 题意:有n个楼,m个防空洞,每个楼有一个坐标和一个人数B,每个防空洞有一个坐标和容纳量C,从楼到防空洞需要的时间是其曼哈顿距离+1,现在给 ...

  3. HDU 3315 My Brute(费用流)

    职务地址:HDU 3315 这个题的思路全然是自己想出来的,自我感觉挺巧妙的. . .(大牛勿喷.. . )对大胆建图又多了一份信心. 详细思路是构造一个二分图,Si连源点.Xi连汇点,流量都是1,费 ...

  4. 网络费用流-最小k路径覆盖

    多校联赛第一场(hdu4862) Jump Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  5. HDU 4862 Jump 费用流

    又是一个看了题解以后还坑了一天的题…… 结果最后发现是抄代码的时候少写了一个负号. 题意: 有一个n*m的网格,其中每个格子上都有0~9的数字.现在你可以玩K次游戏. 一次游戏是这样定义的: 你可以选 ...

  6. HDU 3488--Tour(KM or 费用流)

    因为每个点只能经过一次 所以考虑拆点 这题有坑,有重边.. KM算法 把一个点拆成入点和出点 入点在X部,出点在Y步. 如果u,v之间有路径,就在X部的u点连接Y部的v点 求完美匹配. 当完美匹配的时 ...

  7. 二分图带权匹配 KM算法与费用流模型建立

    [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值之和最大或最小.而二分图的最佳匹配则一定为完备匹配,在此基础上,才要求匹配的边权值之和最大 ...

  8. [BZOJ1937][SHOI2004]Mst最小生成树(KM算法,最大费用流)

    1937: [Shoi2004]Mst 最小生成树 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 802  Solved: 344[Submit][Sta ...

  9. hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))

    Special Fish Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Tota ...

随机推荐

  1. 1988-B. 有序集合

    描述 在C++里,有一个神奇的东西,叫做STL,这里提供了很多简单好用的容器,用来实现常用又很难书写的数据结构,如栈(stack)等.其中,有一个容器叫set,译作“有序集合”.首先,这是一个集合,所 ...

  2. 1058-Tom and Jerry

    描述 Tom和Jerry在10*10的方格中: *...*..... ......*... ...*...*.. .......... ...*.C.... *.....*... ...*...... ...

  3. 一个简单的C#加密解密类

    //DES默认密钥向量 private static byte[] Keys = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; /// < ...

  4. SQLite入门与分析(四)---Page Cache之事务处理(2)

    写在前面:个人认为pager层是SQLite实现最为核心的模块,它具有四大功能:I/O,页面缓存,并发控制和日志恢复.而这些功能不仅是上层Btree的基础,而且对系统的性能和健壮性有关至关重要的影响. ...

  5. Qt5官方demo解析集(36个)

    http://blog.csdn.net/cloud_castle/article/category/2123873 http://blog.csdn.net/cloud_castle/article ...

  6. C#基础精华06(Linq To XML,读取xml文件,写入xml)

    1.XML概述: 可扩展标记语言XML(eXtensible Markup Language)是一种简单灵活的文本格式的可扩展标记语言,侧重于存储数据. 2.XML特点 xml 标记语言 html x ...

  7. WPF中动态添加xaml资源文件

    一.新建一个资源文件,然后设置其Build Actoin(生成操作)为Resource(资源): 二.在App.xaml.cs的StartUp事件或者是你需要的时机代码段写上如下代码: Resourc ...

  8. JavaScript DOM高级程序设计 2.4-try{}catch{}--我要坚持到底!

    先看一段有异常的语句 var sound = 'Roar!'; function myOrneryBeast() { this.style.color='green';//window没有style属 ...

  9. VPN column: PPTP(2)--PPTP协议解析

    zhu_hit原创,如需转载请注明出处.Thanks. PPTP协议大体上可以分为两部分:控制层连接和隧道,下面简要介绍两部分的功能.如果要详细了解PPTP协议请阅读RFC文档. 一. Control ...

  10. 记录遇到的IE8兼容性问题汇总

    1,伪元素:first-child不起作用,需要单独指定样式名称 2,透明度表示方法,尤其在函数中表示 @mixin opacity($value) { -webkit-opacity: $value ...