ural 1421(建图求最大流后求某些边的使用量)
2014-02-13 17:13
357 查看
题意:题目有点长,但其实很简单的,就是给你一个N值,代表有一个N*N的整数矩阵,然后给出每一行的和值,
再给出每一列的和值,问是否存在这样的矩阵,是则输出YES,并输出这个矩阵,否则输出NO,若答案不
唯一则输出一个答案即可。
解题思路:网络流的建图题,多加两个点分别为源点与汇点,源点与代表各行的点相连,容量为行和;
代表各列的点与汇点相连,容量为列和;
行与每一个列都连一条边,容量为100,每一条边对应一个矩阵中的元素。
对上图求最大流,若最大流的值为所有列和或所有行和的值则存在,并根据边标号读出矩阵中的元素,
否则不存在。(注意:建图注意方向,边标号要记清楚,每建一条边,边标号都会加两次,一次是存
边,一次是存反向边)。
31msC++代码
#include <stdio.h>
#include <iostream>
#include <string.h>
#define VM 100010
#define EM 400010
using namespace std;
const int inf = 0x3f3f3f3f;
struct E
{
int to, frm, nxt, cap;
}edge[EM];
int head[VM], e;//建图时初始化
int dep[VM], gap[VM];//ISAP函数内初始化
void init()
{
e = 0;
memset(head, -1, sizeof(head));
}
int addEdge(int cu, int cv, int cw)
{
edge[e].frm = cu;
edge[e].to = cv;
edge[e].cap = cw;
edge[e].nxt = head[cu];
head[cu] = e++;
edge[e].frm = cv;
edge[e].to = cu;
edge[e].cap = 0;
edge[e].nxt = head[cv];
head[cv] = e++;
return (e - 1);
}
int que[VM];
void BFS(int des)
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
int front = 0, rear = 0;
dep[des] = 0;
que[rear++] = des;
int u, v;
while (front != rear)
{
u = que[front++];
front = front%VM;
for (int i=head[u]; i!=-1; i=edge[i].nxt)
{
v = edge[i].to;
if (edge[i].cap != 0 || dep[v] != -1)
continue;
que[rear++] = v;
rear = rear % VM;
++gap[dep[v] = dep[u] + 1];
}
}
}
int cur[VM], stack[VM];
//sap模板
int ISAP(int src, int des, int n)//源点、汇点、图中点的总数
{
int res = 0;
BFS(des);
int top = 0;
memcpy(cur, head, sizeof(head));
int u = src, i;
while (dep[src] < n)
{
if (u == des)
{
int temp = inf, inser = n;
for (i=0; i!=top; ++i)
if (temp > edge[stack[i]].cap)
{
temp = edge[stack[i]].cap;
inser = i;
}
for (i=0; i!=top; ++i)
{
edge[stack[i]].cap -= temp;
edge[stack[i]^1].cap += temp;
}
res += temp;
top = inser;
u = edge[stack[top]].frm;
}
if (u != des && gap[dep[u] -1] == 0)
break;
for (i = cur[u]; i != -1; i = edge[i].nxt)
if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
break;
if (i != -1)
{
cur[u] = i;
stack[top++] = i;
u = edge[i].to;
}
else
{
int min = n;
for (i = head[u]; i != -1; i = edge[i].nxt)
{
if (edge[i].cap == 0)
continue;
if (min > dep[edge[i].to])
{
min = dep[edge[i].to];
cur[u] = i;
}
}
--gap[dep[u]];
++gap[dep[u] = min + 1];
if (u != src)
u = edge[stack[--top]].frm;
}
}
return res;
}
int main()
{
int N,i,j,sumr,sumc,c;
while(scanf("%d", &N) != EOF)
{
sumr =sumc = 0;
init();
for(i = 1; i <= N; i++)
{
scanf("%d",&c);
addEdge(1,1+i,c);
sumr += c;
}
for(i = 1; i <= N; i++)
{
for(j = 1; j <= N; j++)
addEdge(1+i,1+N+j,100);
}
for(i = 1; i <= N; i++)
{
scanf("%d",&c);
addEdge(1+N+i,1+N+N+1,c);
sumc += c;
}
int ans = ISAP(1,1+N+N+1,1+N+N+1);
if(sumc != sumr || ans != sumr)
printf("NO\n");
else
{
printf("YES\n");
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
if(j == N-1)
printf("%d",100 - edge[i*2*N+2*j+2*N].cap);
else
printf("%d ",100 - edge[i*2*N+2*j+2*N].cap);
}
printf("\n");
}
}
}
return 0;
}
再给出每一列的和值,问是否存在这样的矩阵,是则输出YES,并输出这个矩阵,否则输出NO,若答案不
唯一则输出一个答案即可。
解题思路:网络流的建图题,多加两个点分别为源点与汇点,源点与代表各行的点相连,容量为行和;
代表各列的点与汇点相连,容量为列和;
行与每一个列都连一条边,容量为100,每一条边对应一个矩阵中的元素。
对上图求最大流,若最大流的值为所有列和或所有行和的值则存在,并根据边标号读出矩阵中的元素,
否则不存在。(注意:建图注意方向,边标号要记清楚,每建一条边,边标号都会加两次,一次是存
边,一次是存反向边)。
31msC++代码
#include <stdio.h>
#include <iostream>
#include <string.h>
#define VM 100010
#define EM 400010
using namespace std;
const int inf = 0x3f3f3f3f;
struct E
{
int to, frm, nxt, cap;
}edge[EM];
int head[VM], e;//建图时初始化
int dep[VM], gap[VM];//ISAP函数内初始化
void init()
{
e = 0;
memset(head, -1, sizeof(head));
}
int addEdge(int cu, int cv, int cw)
{
edge[e].frm = cu;
edge[e].to = cv;
edge[e].cap = cw;
edge[e].nxt = head[cu];
head[cu] = e++;
edge[e].frm = cv;
edge[e].to = cu;
edge[e].cap = 0;
edge[e].nxt = head[cv];
head[cv] = e++;
return (e - 1);
}
int que[VM];
void BFS(int des)
{
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
int front = 0, rear = 0;
dep[des] = 0;
que[rear++] = des;
int u, v;
while (front != rear)
{
u = que[front++];
front = front%VM;
for (int i=head[u]; i!=-1; i=edge[i].nxt)
{
v = edge[i].to;
if (edge[i].cap != 0 || dep[v] != -1)
continue;
que[rear++] = v;
rear = rear % VM;
++gap[dep[v] = dep[u] + 1];
}
}
}
int cur[VM], stack[VM];
//sap模板
int ISAP(int src, int des, int n)//源点、汇点、图中点的总数
{
int res = 0;
BFS(des);
int top = 0;
memcpy(cur, head, sizeof(head));
int u = src, i;
while (dep[src] < n)
{
if (u == des)
{
int temp = inf, inser = n;
for (i=0; i!=top; ++i)
if (temp > edge[stack[i]].cap)
{
temp = edge[stack[i]].cap;
inser = i;
}
for (i=0; i!=top; ++i)
{
edge[stack[i]].cap -= temp;
edge[stack[i]^1].cap += temp;
}
res += temp;
top = inser;
u = edge[stack[top]].frm;
}
if (u != des && gap[dep[u] -1] == 0)
break;
for (i = cur[u]; i != -1; i = edge[i].nxt)
if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
break;
if (i != -1)
{
cur[u] = i;
stack[top++] = i;
u = edge[i].to;
}
else
{
int min = n;
for (i = head[u]; i != -1; i = edge[i].nxt)
{
if (edge[i].cap == 0)
continue;
if (min > dep[edge[i].to])
{
min = dep[edge[i].to];
cur[u] = i;
}
}
--gap[dep[u]];
++gap[dep[u] = min + 1];
if (u != src)
u = edge[stack[--top]].frm;
}
}
return res;
}
int main()
{
int N,i,j,sumr,sumc,c;
while(scanf("%d", &N) != EOF)
{
sumr =sumc = 0;
init();
for(i = 1; i <= N; i++)
{
scanf("%d",&c);
addEdge(1,1+i,c);
sumr += c;
}
for(i = 1; i <= N; i++)
{
for(j = 1; j <= N; j++)
addEdge(1+i,1+N+j,100);
}
for(i = 1; i <= N; i++)
{
scanf("%d",&c);
addEdge(1+N+i,1+N+N+1,c);
sumc += c;
}
int ans = ISAP(1,1+N+N+1,1+N+N+1);
if(sumc != sumr || ans != sumr)
printf("NO\n");
else
{
printf("YES\n");
for(i = 0; i < N; i++)
{
for(j = 0; j < N; j++)
{
if(j == N-1)
printf("%d",100 - edge[i*2*N+2*j+2*N].cap);
else
printf("%d ",100 - edge[i*2*N+2*j+2*N].cap);
}
printf("\n");
}
}
}
return 0;
}
相关文章推荐
- ORACLE使用max查询某张表字段的最大值
- 解决使用Win2003远程桌面连接服务器的时候就报超过最大连接数错误问题
- 51NOD 1421 最大MOD值&&Codeforces 484 B. Maximum Value(筛法 + 二分)
- 安装MySQL,本地计算机上的服务启动后停止。某些服务在未由其他服务或程序使用时将自动停止
- 超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
- 【java入门】使用选择法确定输入最大值
- C++中使用vector建立最大堆和最小堆
- iOS ARC模式下,某些文件使用非ARC模式
- 使用Java语言实现,自己主动生成10个整数(1~100,求出生成数列中的最大值和最小值,不同意使用Arrays类的sort方法
- 调整Java虚拟机JVM的最大内存使用大小
- 使用RenderScript库,在某些手机或Android版本奔溃的问题
- cocos2dx3.2 某些UI白屏或使用ClippingNode造成部分手机白屏
- 华为机试题:输入两个超长整型构成的字符串,其间使用一个空格分隔,每个字符串最大长度为100个字符。求第一个整数除以第二个整数以后的余数。。
- C++使用两个栈实现一个可以获取栈中最大值和最小值的栈
- 使用模版列来控制在一个GridView中某些列有热连接,某些列无热连接
- 读取 XML 数据时,超出最大字符串内容长度配额 (8192)。通过更改在创建 XML 读取器时所使用的 XmlDictionaryReaderQuotas 对象的 MaxStringContentLength 属性,可增加此配额。
- 使用git和github,突破心里障碍,觉得使用某些工具很麻烦,其实花不了多久
- JdbcTemplate 在使用连接池的情况下,数据库连接仍超出最大回话数可能的原因
- 51Nod-1421-最大MOD值
- 键盘输入3*3的整数矩阵,求两条对角线中最小的元素和最大的元素,使用普通指针变量实现。