FZU - 2295 Human life (最大权闭合子图)
题目链接
题目分析
题意:你在玩一个游戏,在其中你可以通过学习一些技能,但是学习某些技能之前,可能还要学习一些其他的技能,并且学习任何技能都有一定的花费;
而我们可以通过掌握某些工作以获取报酬,为了掌握这一工作,我们必须学会特定的技能。
不过有些工作彼此之间是冲突的,简单来说:如果你掌握了工作A,那么将无法掌握工作B
思路:
由于技能之间也存在依赖关系,但实际上如果要获取某一工作的报酬,那么必须选择这个工作的前置技能以及前置技能的前置技能,
那么显然,这些形成依赖关系的技能都是这一工作的前置技能,所以我们的问题就是求最大权闭合子图了。
我们在工作和其所有的前置技能之间建一条容量为inf的边,然后由所有的技能向汇点建一条容量为这一技能学习消耗的边,
再由源点向每个工作建一条容量为这一工作报酬的边。
这个地方还加上了一个条件,有些工作无法同时获取,不过这个地方产生冲突最大对数为5个,那么我们枚举所有的情况就好了,
一共2^5 = 32种,根据每种状态来决定可选取的工作,并构建这一顶点及其相关的边
然后根据:最大闭合子图的权值 = 所有权值为正的结点的权值之和 - 最小割(最大流)求出答案
顺便吐糟一下这个题,首先这个OJ的C++环境不是C11标准,也就是说不支持大括号给结构体变量赋值,比如这样:

我这个语法写了近一年了,从未出错,这个评测机第一次把我这里卡了,一直CE,还不给出错误信息QAQ....
代码区
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include<fstream>
#include<vector>
#include<stack>
#include <map>
#include <iomanip>
#define bug cout << "**********" << endl
#define show(x,y) cout<<"["<<x<<","<<y<<"] "
//#define LOCAL = 1;
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + ;
const int Max = 1e3+ ; struct Edge
{
int to, next, flow;
}edge[Max << ]; int T, n, m, k;
int s, t;
vector<int>edge_raw[Max]; //记录原图边的关系
int vis[][]; //vis[i][j]记录j是否是i的前置结点
int select[]; //记录某点是否被删除(处理工作冲突)
int use[]; //记录每个点的是否使用(处理技能之间的前置关系)
int head[], tot;
int cost[]; //记录了学习每个技能的花费
int val[]; //记录掌握每个工作的报酬
int dis[]; //记录i的层次编号(Dinic中使用)
pair<int, int>fight[]; //记录冲突 void init()
{
s = , t = n + m + ; //1-m为技能,m+1~n+m为工作
memset(vis, , sizeof(vis));
memset(use, , sizeof(use));
for (int i = ;i <= n; i++)
edge_raw[i].clear();
} void add(int u, int v, int flow)
{
edge[tot].to = v;
edge[tot].flow = flow;
edge[tot].next = head[u];
head[u] = tot++; edge[tot].to = u;
edge[tot].flow = ;
edge[tot].next = head[v];
head[v] = tot++;
} void dfs(int u) //找到每个技能所有的前置技能
{
use[u] = true; //代表u已经访问
for (int i = ; i < edge_raw[u].size(); i++)
{
int v = edge_raw[u][i];
vis[u][v] = true;
if (!use[v]) //自己是自己的前置结点
{
dfs(v);
}
for (int j = ;j <= n;j++) //枚举这个点的前置结点
{
if (vis[v][j]) //v的前置结点是j,那么u的前置结点也是j
{
vis[u][j] = true;
}
}
}
} bool bfs() //判断连通性,将图分层次
{
queue<int>q;
memset(dis, -, sizeof(dis));
dis[s] = ;
q.push(s);
while (!q.empty())
{
int u = q.front();q.pop(); for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if (dis[v] == - && edge[i].flow > )
{
dis[v] = dis[u] + ;
q.push(v);
if (v == t) return true;
}
}
}
return false;
} int dfs(int u, int flow_in)
{
if (u == t) return flow_in;
int flow_out = ; //实际流出流量
for (int i = head[u];i != -;i = edge[i].next)
{
int v = edge[i].to;
if (dis[v] == dis[u] + && edge[i].flow > )
{
int flow_part = dfs(v, min(flow_in, edge[i].flow));
if (flow_part == )continue; //无法形成增广路
flow_in -= flow_part;
flow_out += flow_part;
edge[i].flow -= flow_part;
edge[i ^ ].flow += flow_part;
if (flow_in == )break;
}
}
return flow_out;
} int max_flow()
{
int sum = ;
while (bfs())
{
sum += dfs(s, inf);
}
return sum;
} int main()
{
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
scanf("%d", &T);
while (T--)
{
scanf("%d%d%d", &n, &m, &k);
init();
for (int i = , num;i <= n;i++)
{
scanf("%d%d", cost + i, &num);
for (int j = ;j <= num;j++)
{
int pre; //技能i的前置技能点
scanf("%d", &pre);
edge_raw[i].push_back(pre); //构建直系前置技能关系
}
}
for (int i = ;i <= n;i++)
{
if (!use[i])dfs(i);
} for (int i = n + , cnt; i <= n + m;i++) //工作编号n +1 ~n+m
{
scanf("%d%d", val + i, &cnt);
while (cnt--)
{
int x;
scanf("%d", &x);
vis[i][x] = true;
for (int j = ;j <= n;j++)
{
if (vis[x][j]) //求出工作所有的前置技能
vis[i][j] = true;
}
}
} for (int i = ;i < k;i++)
{
scanf("%d %d", &fight[i].first, &fight[i].second);
}
int max_val = ; for (int state = ;state < ( << k);state++) //枚举状态,对应位置为1表示选first,0表示选second
{
memset(select, , sizeof(select)); //0表示不删除
memset(head, -, sizeof(head));tot = ;
for (int i = ;i < k;i++)
{
if ((state >> i) & )
{
select[fight[i].second] = true; //删除second
}
else
{
select[fight[i].first] = true; //删除first
}
}
int sum = ; //记录总价值
for (int i = + n;i <= n + m;i++)
{
if (select[i - n])continue; //当前状态下不不选取的工作就不用构建与之有关的边了
sum += val[i];
add(s, i, val[i]); //由源点向可选工作构建一条容量为当前工作报酬的边
for (int j = ;j <= n;j++)
{
if (vis[i][j])
{
add(i, j, inf); //有工作向其所有前置技能点建一条容量为inf的边
}
}
}
for (int i = ;i <= n;i++) //由所有技能向汇点构建一条容量为其花费的边
{
add(i, t, cost[i]);
}
int flow = max_flow();
max_val = max(max_val, sum - flow); //最大闭合子图的权值 = 所有权值为正的结点的权值之和 - 最小割(最大流)
}
printf("%d\n", max_val);
}
return ;
}
FZU 2295
FZU - 2295 Human life (最大权闭合子图)的更多相关文章
- FZU - 2295 Human life:网络流-最大权闭合子图-二进制优化-第九届福建省大学生程序设计竞赛
目录 Catalog Solution: (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦 http://acm.fzu.edu.cn/problem.php?pid=2295 htt ...
- Human life FZU - 2295 最大权闭合子图(第一次遇到被教育了)
Xzz is playing a MMORPG "human life". In this game, there are N different skills. Some ski ...
- BZOJ1565 [NOI2009]植物大战僵尸(拓扑排序 + 最大权闭合子图)
题目 Source http://www.lydsy.com/JudgeOnline/problem.php?id=1565 Description Input Output 仅包含一个整数,表示可以 ...
- HDU 3879 Base Station(最大权闭合子图)
经典例题,好像说可以转化成maxflow(n,n+m),暂时只可以勉强理解maxflow(n+m,n+m)的做法. 题意:输入n个点,m条边的无向图.点权为负,边权为正,点权为代价,边权为获益,输出最 ...
- [BZOJ 1497][NOI 2006]最大获利(最大权闭合子图)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1497 分析: 这是在有向图中的问题,且边依赖于点,有向图中存在点.边之间的依赖关系可以 ...
- HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4971 Description There's a company with several ...
- HDU5855 Less Time, More profit(最大权闭合子图)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5855 Description The city planners plan to build ...
- HDU5772 String problem(最大权闭合子图)
题目..说了很多东西 官方题解是这么说的: 首先将点分为3类 第一类:Pij 表示第i个点和第j个点组合的点,那么Pij的权值等于w[i][j]+w[j][i](表示得分) 第二类:原串中的n个点每个 ...
- SCU3109 Space flight(最大权闭合子图)
嗯,裸的最大权闭合子图. #include<cstdio> #include<cstring> #include<queue> #include<algori ...
随机推荐
- 30行左右代码实现一个类似httprunner的接口框架
框架的最终归宿往往是领域语言+模板解析. 首先先约定一种所要执行操作的表述格式.然后通过模板解析将描述语言转化为代码进行执行.例如,我们可以使用以下yaml文件描述多个步骤并且需要关联的接口: api ...
- 配置centos7阿里镜像源和epel源
[root@runstone yum.repos.d]# pwd /etc/yum.repos.d [root@runstone yum.repos.d]# cat aliBase.repo #镜像源 ...
- 使用python3安装frida-tools出错
执行安装命令 pip3.6 install frida-tools 得到错误信息 error: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] c ...
- 2018-2019-2 网络对抗技术 20165222 Exp 8 Web基础
1.实践内容 (1).Web前端HTML 能正常安装.启停Apache.理解HTML,理解表单,理解GET与POST方法,编写一个含有表单的HTML. 使用service apache2 start启 ...
- Flutter移动电商实战 --(53)购物车_商品列表UI框架布局
cart_page.dart 清空原来写的持久化的代码; 添加对应的引用,stless生成一个静态的类.建议始终静态的类,防止重复渲染 纠正个错误,上图的CartPage单词拼错了,这里改过来防止后面 ...
- PHP try catch 如何使用
<?php try { if (file_exists('test_try_catch.php')) { require ('test_try_catch.php'); } else { ...
- OpenJudge数据结构与算法-计算点的距离并排序
/*================================================================== 距离排序 总时间限制: 1000ms 内存限制: 65536k ...
- 算法习题---4-3黑白棋(UVa220)
一:题目 系统提示当前旗手W/B(白/黑)下子,例如W下子,那么W下的位置必须是夹住黑色棋子的位置才可以. 夹住方式:横向.竖向.斜向 注意落子后将夹住的黑棋吞噬变为白棋 (一)题目详解 .棋盘以数组 ...
- 运行时给java对象动态的属性赋值
运行时给java对象动态的属性赋值 如何给java对象动态的属性赋值(也就是在代码执行的时候才决定给哪个属性赋值) 1.自定义一个工具类ReflectHelper,代码如下所示: pa ...
- No WebApplicationContext found: no ContextLoaderListener registered
修改前运行报错:No WebApplicationContext found: no ContextLoaderListener registered? <web-app> <dis ...