HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)
题目
Source
http://acm.hdu.edu.cn/showproblem.php?pid=4971
Description
There's a company with several projects to be done. Finish a project will get you profits. However, there are some technical problems for some specific projects. To solve the problem, the manager will train his employee which may cost his budget. There may be dependencies between technical problems, for example, A requires B means you need to solve problem B before solving problem A. If A requires B and B requires A, it means that you should solve them at the same time. You can select which problems to be solved and how to solve them freely before finish your projects. Can you tell me the maximum profit?
Input
The first line of the input is a single integer T(<=100) which is the number of test cases.
Each test case contains a line with two integer n(<=20) and m(<=50) which is the number of project to select to complete and the number of technical problem.
Then a line with n integers. The i-th integer(<=1000) means the profit of complete the i-th project.
Then a line with m integers. The i-th integer(<=1000) means the cost of training to solve the i-th technical problem.
Then n lines. Each line contains some integers. The first integer k is the number of technical problems, followed by k integers implying the technical problems need to solve for the i-th project.
After that, there are m lines with each line contains m integers. If the i-th row of the j-th column is 1, it means that you need to solve the i-th problem before solve the j-th problem. Otherwise the i-th row of the j-th column is 0.
Output
For each test case, please output a line which is "Case #X: Y ", X means the number of the test case and Y means the the maximum profit.
Sample Input
4
2 3
10 10
6 6 6
2 0 1
2 1 2
0 1 0
1 0 0
0 0 0
2 3
10 10
8 10 6
1 0
1 2
0 1 0
1 0 0
0 0 0
2 3
10 10
8 10 6
1 0
1 2
0 1 0
0 0 0
0 0 0
2 3
10 10
8 10 6
1 0
1 2
0 0 0
1 0 0
0 0 0
Sample Output
Case #1: 2
Case #2: 4
Case #3: 4
Case #4: 6
分析
题目大概说有n个可以获益的项目,还有m个有一定代价的技术问题。解决某个项目需要先解决某些技术问题;而解决某些技术问题又需要解决另外一些技术问题;如果两个技术问题互相依赖,则要同时解决它们。问能获得的最少收益是多少。
m个技术问题看成点,依赖关系看成边,然后求强连通分量并缩点形成DAG,这样就是最大权闭合子图问题了,最小割解决即可。
代码
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 111
#define MAXM 2222 struct Edge{
int v,cap,flow,next;
}edge[MAXM];
int vs,vt,NE,NV;
int head[MAXN]; void addEdge(int u,int v,int cap){
edge[NE].v=v; edge[NE].cap=cap; edge[NE].flow=0;
edge[NE].next=head[u]; head[u]=NE++;
edge[NE].v=u; edge[NE].cap=0; edge[NE].flow=0;
edge[NE].next=head[v]; head[v]=NE++;
} int level[MAXN];
int gap[MAXN];
void bfs(){
memset(level,-1,sizeof(level));
memset(gap,0,sizeof(gap));
level[vt]=0;
gap[level[vt]]++;
queue<int> que;
que.push(vt);
while(!que.empty()){
int u=que.front(); que.pop();
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(level[v]!=-1) continue;
level[v]=level[u]+1;
gap[level[v]]++;
que.push(v);
}
}
} int pre[MAXN];
int cur[MAXN];
int ISAP(){
bfs();
memset(pre,-1,sizeof(pre));
memcpy(cur,head,sizeof(head));
int u=pre[vs]=vs,flow=0,aug=INF;
gap[0]=NV;
while(level[vs]<NV){
bool flag=false;
for(int &i=cur[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap!=edge[i].flow && level[u]==level[v]+1){
flag=true;
pre[v]=u;
u=v;
//aug=(aug==-1?edge[i].cap:min(aug,edge[i].cap));
aug=min(aug,edge[i].cap-edge[i].flow);
if(v==vt){
flow+=aug;
for(u=pre[v]; v!=vs; v=u,u=pre[u]){
edge[cur[u]].flow+=aug;
edge[cur[u]^1].flow-=aug;
}
//aug=-1;
aug=INF;
}
break;
}
}
if(flag) continue;
int minlevel=NV;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(edge[i].cap!=edge[i].flow && level[v]<minlevel){
minlevel=level[v];
cur[u]=i;
}
}
if(--gap[level[u]]==0) break;
level[u]=minlevel+1;
gap[level[u]]++;
u=pre[u];
}
return flow;
} int n,m; int profit[22],cost[55];
int need[22][55],G[55][55]; int top,stack[MAXN];
bool instack[MAXN];
int dn,dfn[MAXN],low[MAXN];
int bn,belong[MAXN];
void tarjan(int u){
dfn[u]=low[u]=++dn;
stack[++top]=u; instack[u]=1;
for(int v=1; v<=m; ++v){
if(u==v || G[u][v]==0) continue;
if(dfn[v]==0){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(instack[v]){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
int v; ++bn;
do{
v=stack[top--];
instack[v]=0;
belong[v]=bn;
}while(u!=v);
}
} int main(){
int t;
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i){
scanf("%d",profit+i);
}
for(int i=1; i<=m; ++i){
scanf("%d",cost+i);
}
int a,b;
for(int i=1; i<=n; ++i){
need[i][0]=0;
scanf("%d",&a);
while(a--){
scanf("%d",&b);
need[i][++need[i][0]]=b+1;
}
}
for(int i=1; i<=m; ++i){
for(int j=1; j<=m; ++j){
scanf("%d",&G[i][j]);
}
} top=0; dn=0; bn=0;
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
for(int i=1; i<=m; ++i){
if(dfn[i]==0) tarjan(i);
}
vs=0; vt=n+bn+1; NV=vt+1; NE=0;
memset(head,-1,sizeof(head));
int tot=0;
for(int i=1; i<=n; ++i){
tot+=profit[i];
addEdge(vs,i,profit[i]);
for(int j=1; j<=need[i][0]; ++j){
addEdge(i,belong[need[i][j]]+n,INF);
}
}
for(int i=1; i<=bn; ++i){
int cnt=0;
for(int j=1; j<=m; ++j){
if(belong[j]==i) cnt+=cost[j];
}
addEdge(i+n,vt,cnt);
}
for(int i=1; i<=m; ++i){
for(int j=1; j<=m; ++j){
if(G[i][j]==0 || belong[i]==belong[j]) continue;
addEdge(belong[i]+n,belong[j]+n,INF);
}
}
printf("Case #%d: %d\n",cse,tot-ISAP());
}
return 0;
}
HDU4971 A simple brute force problem.(强连通分量缩点 + 最大权闭合子图)的更多相关文章
- HDU 4971 A simple brute force problem.
A simple brute force problem. Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged o ...
- A simple brute force problem.
hdu4971:http://acm.hdu.edu.cn/showproblem.php?pid=4971 题意:给你n个项目,每完成一个项目会有一定的收益,但是为了完成某个项目,要先学会一些技能, ...
- HDU 4971 - A simple brute force problem【最大权闭合图】
有n(20)个工程,完成每个工程获得收益是p[i],m(50)个需要解决的难题,解决每个难题花费是c[i] 要完成第i个工程,需要先解决ki个问题,具体哪些问题,输入会给出 每个难题之间可能有依赖关系 ...
- 【最小割】HDU 4971 A simple brute force problem.
说是最大权闭合图.... 比赛时没敢写.... 题意 一共同拥有n个任务,m个技术 完毕一个任务可盈利一些钱,学习一个技术要花费钱 完毕某个任务前须要先学习某几个技术 可是可能在学习一个任务前须要学习 ...
- hdu - 4971 - A simple brute force problem.(最大权闭合图)
题意:n(n <= 20)个项目,m(m <= 50)个技术问题,做完一个项目能够有收益profit (<= 1000),做完一个项目必须解决对应的技术问题,解决一个技术问题须要付出 ...
- HDU 3861 The King’s Problem 强连通分量 最小路径覆盖
先找出强连通分量缩点,然后就是最小路径覆盖. 构造一个二分图,把每个点\(i\)拆成两个点\(X_i,Y_i\). 对于原图中的边\(u \to v\),在二分图添加一条边\(X_u \to Y_v\ ...
- uva 11324 The Largest Clique(强连通分量缩点+DAG动态规划)
http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=25&page=sh ...
- poj 2762 Going from u to v or from v to u?(强连通分量+缩点重构图+拓扑排序)
http://poj.org/problem?id=2762 Going from u to v or from v to u? Time Limit: 2000MS Memory Limit: ...
- LA 4287 等价性证明(强连通分量缩点)
https://vjudge.net/problem/UVALive-4287 题意: 给出n个结点m条边的有向图,要求加尽量少的边,使得新图强连通. 思路:强连通分量缩点,然后统计缩点后的图的每个结 ...
随机推荐
- Javascript异步编程方法总结
现在我们有三个函数,f1, f2, f3 按正常的思路我们会这样写代码: function f1 (){}; function f2 (){}; function f3 (){}; //在这里调用函数 ...
- 实现iOS前台时的推送弹窗效果
原文链接 或许很多童鞋还不知道,在 iOS 中收到推送通知时,如果 App 处于前台运行的情况下,推送的顶部弹窗是不会弹出来的. 然而就是有很多**的产品经理都会提出类似这样的**需求:那就是在 Ap ...
- Clr Via C#读书笔记---线程基础
趣闻:我是一个线程:http://kb.cnblogs.com/page/542462/ 进程与线程 进程:应用程序的一个实例使用的资源的集合.每个进程都被赋予了一个虚拟地址空间. 线程:对CPU进行 ...
- MVC – 7.Razor 语法
7.1 Razor视图引擎语法 Razor通过理解标记的结构来实现代码和标记之间的顺畅切换. @核心转换字符,用来 标记-代码 的转换字符串. 语境A: @{ string rootName=&quo ...
- ActiveMQ的几种集群配置
ActiveMQ是一款功能强大的消息服务器,它支持许多种开发语言,例如Java, C, C++, C#等等.企业级消息服务器无论对服务器稳定性还是速度,要求都很高,而ActiveMQ的分布式集群则能很 ...
- 无废话Android之activity的生命周期、activity的启动模式、activity横竖屏切换的生命周期、开启新的activity获取他的返回值、利用广播实现ip拨号、短信接收广播、短信监听器(6)
1.activity的生命周期 这七个方法定义了Activity的完整生命周期.实现这些方法可以帮助我们监视其中的三个嵌套生命周期循环: (1)Activity的完整生命周期 自第一次调用onCrea ...
- Application.ProcessMessages用法
参考:http://cqujsjcyj.iteye.com/blog/380926 我想你可能还有点模糊.举个例子容易明白:假如你的窗体上有两个按钮,一个“计算”,一个“停止”, 如果你的计算是密集运 ...
- CentOS-6.5安装配置Tengine
一.安装pcre: cd /usr/local/src wget http://downloads.sourceforge.net/project/pcre/pcre/8.34/pcre-8.34.t ...
- lvs+keepalived 负载均衡
LVS是一个开源的软件,可以实现LINUX平台下的简单负载均衡.LVS是Linux Virtual Server的缩写,意思是Linux虚拟服务器.目前有三种IP负 载均衡技术(VS/NAT.VS/T ...
- Jenkins搭建
1.添加仓库: sudo wget -O /etc/yum.repos.d/jenkins.repo \ http://jenkins-ci.org/redhat/jenkins.repo sudo ...