poj_3436 网络最大流
题目大意
生产电脑的工厂将一台电脑分成P个部件来进行流水线生产组装,有N个生产车间,每个车间可以将一个半成品电脑添加某些部件,使之成为另一个半成品电脑或者成为一台完好的电脑,且每个车间有一个效率,即在单位时间内可以将K个半成品组装为另外K个半成品或者完好的电脑。每个车间在组装完成之后,都将组装后的半成品送到另外一个车间,成品直接送到成品区。
现在给出这N个车间的组装原部件集合以及组装后的部件集合(其中 in[1,2,3...p]中 in[i]表示第i种组装元部件,out[1,2,3...p]中out[i]表示第i种组装后的部件。且in[i] = 0表示元部件集合中必须没有第i种部件,in[i]=1表示元部件集合中必须有第i种部件,in[i] = 2表示元部件集合中第i种部件可有可无;out[i]=0表示组装后的部件集合中没有第i种部件,out[i]=1表示组装后的集合中有第i种部件),以及组装效率。求怎样合理的分配N个车间之间的流量,使得组装效率最大。
题目分析
在本题中的最大效率,可以视为各个车间构成的网络图的最大流量。那么,如何构造网络流图求出最大流量呢?
首先考虑将每个车间视为一个节点,若车间A的组装后的部件集合可以被车间B接受,那么单向连接车间A和B。但是,若车间A连接了车间B和车间C,那么A->B和A->C之间的路径容量无法控制。所以这种建图方式不好。
再考虑将每个车间拆分为两个节点,一个入节点,表示车间的组装原部件集合,一个出节点,表示车间组装后的部件集合,在入节点和出节点之间用一条容量为K的路径连接起来。若车间A的组装后部件集合可以被车间B的组装原部件集合所接受,那么连接车间A的出节点和车间B的入节点,同时,容量设为无穷大,这是因为车间的效率受其原部件-->组装后部件的组装效率决定,即车间的入节点到出节点的容量决定。
在构造好的图上从源点到汇点找最大流量,即为最大效率。
实现
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define MAX_NODE 150
#define MAX_EDGE_NUM 300
#define INFINITE 1 << 25
#define min(a, b) a<b? a:b
struct Edge{
int from;
int to;
int w;
int next;
int rev;
bool operator == (const pair<int, int>& p){
return from == p.first && to == p.second;
}
};
Edge gEdges[MAX_EDGE_NUM]; int gEdgeCount;
int gFlow[MAX_NODE][MAX_NODE];
int gGap[MAX_NODE];
int gDist[MAX_NODE];
int gHead[MAX_NODE];
int gPre[MAX_NODE];
int gPath[MAX_NODE]; int gSource, gDestination;
void InsertEdge(int u, int v, int w){
Edge* it = find(gEdges, gEdges + gEdgeCount, pair<int, int>(u, v));
if (it != gEdges + gEdgeCount){
it->w = w;
}
else{
int e1 = gEdgeCount;
gEdges[e1].from = u;
gEdges[e1].to = v;
gEdges[e1].w = w;
gEdges[e1].next = gHead[u];
gHead[u] = e1; gEdgeCount++;
int e2 = gEdgeCount;
gEdges[e2].from = v;
gEdges[e2].to = u;
gEdges[e2].w = 0;
gEdges[e2].next = gHead[v];
gHead[v] = e2; gEdges[e1].rev = e2;
gEdges[e2].rev = e1;
gEdgeCount++;
}
} void Bfs(){
memset(gGap, 0, sizeof(gGap));
memset(gDist, -1, sizeof(gDist));
gGap[0] = 1;
gDist[gDestination] = 0;
queue<int>Q;
Q.push(gDestination);
while (!Q.empty()){
int n = Q.front();
Q.pop();
for (int e = gHead[n]; e != -1; e = gEdges[e].next){
int v = gEdges[e].to;
if (gDist[v] >= 0)
continue;
gDist[v] = gDist[n] + 1;
gGap[gDist[v]] ++;
Q.push(v);
}
}
} int ISAP(int n){ // n为节点的数目
Bfs();
int u = gSource;
int e, d;
int ans = 0;
while (gDist[gSource] <= n){
if (u == gDestination){ //增广
int min_flow = INFINITE;
for (e = gPath[u]; u != gSource; e = gPath[u = gPre[u]]){ //注意,先u = gPre[u], 再取 e = gPath[u]
min_flow = min(min_flow, gEdges[e].w);
}
u = gDestination;
for (e = gPath[u]; u != gSource; e = gPath[u = gPre[u]]){
gEdges[e].w -= min_flow;
gEdges[gEdges[e].rev].w += min_flow; gFlow[gPre[u]][u] += min_flow;
}
ans += min_flow;
}
for (e = gHead[u]; e != -1; e = gEdges[e].next){
if (gEdges[e].w > 0 && gDist[u] == gDist[gEdges[e].to] + 1)
break;
}
if (e >= 0){ //向前推进
gPre[gEdges[e].to] = u; //前一个点
gPath[gEdges[e].to] = e;//该点连接的前一个边
u = gEdges[e].to;
}
else{
d = n;
for (e = gHead[u]; e != -1; e = gEdges[e].next){
if (gEdges[e].w > 0) //需要能够走通才行!!
d = min(d, gDist[gEdges[e].to]);
}
if (--gGap[gDist[u]] == 0) //gap优化
break; gDist[u] = d+1; //重标号 ++gGap[gDist[u]]; //更新 gap!!
if (u != gSource)
u = gPre[u];//回溯
}
}
return ans;
} struct Node{
int id;
int p;
int component[12];
bool CanConnect(const Node& node){
for (int i = 0; i < p; i++){
if (component[i] == 0 && node.component[i] == 1 || component[i] == 1 && node.component[i] == 0)
return false;
}
return true;
}
};
Node gNodes[MAX_NODE]; void BuildGraph(int n){
for (int i = 2; i <= n + 1; i++){
if (gNodes[1].CanConnect(gNodes[i]))
InsertEdge(1, i, INFINITE);
}
for (int i = n+2; i <= 2*n + 1; i++){
for (int j = 2; j <= n + 1; j++){
if (j + n != i && gNodes[i].CanConnect(gNodes[j]))
InsertEdge(i, j, INFINITE); }
}
for (int i = n + 2; i <= 2 * n + 1; i++){
if (gNodes[i].CanConnect(gNodes[2*n+2]))
InsertEdge(i, 2*n+2, INFINITE);
}
}
void print_graph(int n){
for (int u = 1; u <= n; u++){
printf("node %d links to ", u);
for (int e = gHead[u]; e != -1; e = gEdges[e].next)
printf("%d(flow = %d) ", gEdges[e].to, gEdges[e].w);
printf("\n");
}
} int main(){
int p, n, w, u, v;
while (scanf("%d %d", &p, &n) != EOF){ memset(gFlow, 0, sizeof(gFlow));
memset(gHead, -1, sizeof(gHead));
gEdgeCount = 0; int node_id = 1; //构造源点
gNodes[node_id].p = p;
for (int i = 0; i < p; i++){
gNodes[node_id].component[i] = 0;
}
node_id++; for (int i = 0; i < n; i++){
scanf("%d", &w);
u = node_id;
gNodes[u].p = p;
for (int k = 0; k < p; k++){
scanf("%d", &gNodes[u].component[k]);
} v = node_id + n;
gNodes[v].p = p;
for (int k = 0; k < p; k++){
scanf("%d", &gNodes[v].component[k]);
} node_id++;
InsertEdge(u, v, w);
}
node_id = 2 * n + 2;
gNodes[node_id].p = p;
for (int i = 0; i < p; i++){ //构造汇点
gNodes[node_id].component[i] = 1;
}
gSource = 1; gDestination = 2 * n + 2;
BuildGraph(n);
// print_graph(2 * n + 2);
int result = ISAP(2 * n + 2);
printf("%d", result);
int count = 0;
vector<pair<int, int> > edge_vec;
for (int i = n + 2; i <= 2 * n + 1; i++){
for (int j = 2; j <= n + 1; j++){
if (i != j + n && gFlow[i][j] > 0){
count++;
edge_vec.push_back(pair<int, int>(i, j));
}
}
}
printf(" %d\n", count);
for (int k = 0; k < count; k ++){
int i = edge_vec[k].first;
int j = edge_vec[k].second;
printf("%d %d %d\n", i - n - 1, j - 1, gFlow[i][j]);
}
}
return 0;
}
poj_3436 网络最大流的更多相关文章
- P3376 【模板】网络最大流
P3376 [模板]网络最大流 题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点 ...
- HDU 3549 网络最大流再试
http://acm.hdu.edu.cn/showproblem.php?pid=3549 同样的网络最大流 T了好几次原因是用了cout,改成printf就A了 还有HDU oj的编译器也不支持以 ...
- 一般增广路方法求网络最大流(Ford-Fulkerson算法)
/* Time:2015-6-18 接触网络流好几天了 写的第一个模版————Ford-Fulkerson算法 作用:求解网络最大流 注意:源点是0 汇点是1 如果题目输入的是1到n 请预处理减1 * ...
- 算法模板——Dinic网络最大流 2
实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...
- 算法模板——Dinic网络最大流 1
实现功能:同sap网络最大流 今天第一次学Dinic,感觉最大的特点就是——相当的白话,相当的容易懂,而且丝毫不影响复杂度,顶多也就是代码长个几行 主要原理就是每次用spfa以O(n)的时间复杂度预处 ...
- 图论算法-网络最大流【EK;Dinic】
图论算法-网络最大流模板[EK;Dinic] EK模板 每次找出增广后残量网络中的最小残量增加流量 const int inf=1e9; int n,m,s,t; struct node{int v, ...
- 网络最大流算法—EK算法
前言 EK算法是求网络最大流的最基础的算法,也是比较好理解的一种算法,利用它可以解决绝大多数最大流问题. 但是受到时间复杂度的限制,这种算法常常有TLE的风险 思想 还记得我们在介绍最大流的时候提到的 ...
- 洛谷 P3376 【【模板】网络最大流】
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包含三个正整数ui. ...
- 洛谷P3376 【模板】网络最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
随机推荐
- Thrift RPC框架介绍
u 简介 Thrift是一种开源的跨语言的RPC服务框架.Thrift最初由facebook公司开发的,在2007年facebook将其提交apache基金会开源了.对于当时的facebook来说创造 ...
- CodeIgniter在nginx下404 not found
server { listen ; server_name test.platform; charset utf8; root /data/www/platform/trunk; location / ...
- 【转】【Unity】实现全局管理类的几种方式
本文原作者未知,转载自:http://blog.csdn.net/ycl295644/article/details/42458477 如何在Unity中实现全局管理类?由于Unity脚本的运行机制和 ...
- 3D跑马灯效果
睡了13个小时,发烧终于退了,持续2周的感冒看起来终于好了点,这一周一直在看perspective的一些资料,写一个3D跑马灯的效果. 个人感觉主要就是理解视角的概念,也就是perspective和p ...
- 关于listView的item失去焦点不能点击 Item中包含Button 导致抢占焦点
今天发现一个问题.listView的item点击以后进入到下一个页面,下个页面有个返回按钮,直接返回回去以后点击事件不能触发,滑动或者重新打开这个listView,就可以达到原来的效果.后来发现是因为 ...
- 载波帧听Carrier Sense
在发送数据之前,以太网会“帧听”线缆,判断是否有其他数据传输. 如果通信介质上无载波,即没有被占用,则可以利用通信介质进行传送. 网卡芯片PHY具有上述功能. 数据链路层相关技术 共享介质网络 从通信 ...
- WF追忆
前一阵子学习了一下工作流,现在写个总结记录一下这个过程.要弄工作流,首先就要有个界面来画图,做web的,没办法,只能选择javascript和silverlight,找来找去,最后用了Shareide ...
- win7配置ftp服务器
1.安装FTP,打开控制面板,找到程序和功能-->打开或者关闭windows功能,在列表中,展开internet信息服务,勾选FTP服务器,展开WEB管理工具,勾选IIS管理控制台,然后点击确定 ...
- R语言学习笔记之<在Linux上遇到的问题集锦>
Standalone模式:Standalone模式运行的Spark集群对不同的应用程序采用先进先出(FIFO)的顺序进行调度.默认情况下每个应用程序会独占所有可用节点的资源. 现在版本的SparkR只 ...
- 关于Cocos2d-x中音效重复播放问题的解决
在做一些动作的时候,有时候只希望播放一次音效,但是触发音效的前提条件是要按着某个按钮,如果直接把播放音效的语句写在MOVED的case中,就会重复播放音效 解决方法就是把播放音效的语句写在BEGAN的 ...