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 ...
随机推荐
- python常用函数1
map()函数 map()是python 内置 的高届函数 ,接收一个函数 f 和一个list,并通过把函数 f 依次作用在list的每个元素上,得到一个新的 list 并返回. 比如,对于l ...
- [Python]闭包的理解和使用
闭包广泛使用在函数式编程语言中,虽然不是很容易理解,但是又不得不理解. 闭包是什么? 在一些语言中,在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包.闭包可以 ...
- 3、Web server 之httpd2.2 配置说明
http协议实现的程序 静态(httpd, nginx, lighttpd) 动态 (IIS, tomcat, jetty, jboss, resin, websphere, weblogic ...
- Linux之jq
什么是jq?jq是Linux下面把文本字符串格式化成json格式的工具 系统环境:centos 7 一.安装 (1)yum安装 a.安装epel源 # wget http://dl.fedorapro ...
- Bsgs模板
模板最主要的是自己看得舒服,不会给自己留隐患,调起来比较简单,板子有得是,最主要的是改造出适合你的那一套. ——mzz #include<bits/stdc++ ...
- springMVC_配置文件搭建基础环境
SpringMVC与Struts的区别. 一.基础jar包 二.①DispatcherServlet,handelMapping,webAction(colltroller),ModelAndView ...
- T-MAX组--项目冲刺(第一天)
THE FIRST DAY 项目相关 作业相关 具体描述 所属班级 2019秋福大软件工程实践Z班 作业要求 团队作业第五次-项目冲刺 作业正文 T-MAX组--项目冲刺(第一天) 团队名称 T-MA ...
- SVN分支创建与合并
SVN分支 一个branch是某个development line(通常是主线也即trunk)的一个拷贝,branch存在的意义在于,在不干扰trunk的情况下,和trunk并行开发,待开发结束后合并 ...
- 关于python环境下的opencv安装
吐槽: 这一天我终于记起了这个博客.今天搞python环境下的opencv,又弄了一天,很烦躁.之前配置VS的opencv也是花了好久的时间,然后突然发现之前记录在电脑上的文档都找不到了,于是决定还是 ...
- Cisco设备自动定时备份配置
前言 当我们管理的网络设备为个位数的时候,手动的把配置通过tftp方式copy出来还是可以的.但是当我们管理几十台甚至上百台(有点夸张,都这个级别了肯定用专业的运维软件或者开发运维平台进行管理)的时候 ...