pku3281 Dining

题目分析:有N头牛,F种食物,D种饮料,要求给每头牛分配一份食物和一种饮料,每种食物和每种饮料只能供一头牛享用,问最多能满足多少头牛的需要。

建图:建一超级源点标号为0,连上所有的食物,边权为1,建一超级汇点标号为2 * N + F + D + 1,连上所有的饮料,边权为1,在构造N个点和N头牛一一对应,保证每头牛只享用一种食物和一种饮料,边权为1,每头牛享用的食物和对应的构造点相连,边权为1,N头牛在和他喜欢的饮料相连,边权为1。

数据量小,用EK写了下:跑了170多ms

代码
#include<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#define INF 0xfffffff
#define NN 410

int S, T;
int c[NN][NN];
int pre[NN];
int bfs()
{
int que[NN];
int mark[NN];
memset(mark,
0, sizeof(mark));
que[
0] = S;
mark[S]
= 1;
int tail,head, u, i;
tail
= head = 0;
while(head <= tail){
u
= que[head++];
for (i = 0; i <= T; i++){
if (!mark[i] && c[u][i] > 0){
mark[i]
= 1;
que[
++tail] = i;
pre[i]
= u;
if (i == T){
return 1;
}
}
}
}
return 0;
}
void EK()
{
int minf, t;
int maxFlow = 0;
while(bfs()){
minf
= INF;
t
= T;
while(t != S){
if (c[pre[t]][t] < minf){
minf
= c[pre[t]][t];
}
t
= pre[t];
}
maxFlow
+= minf;
t
= T;
while(t != S){
c[pre[t]][t]
-= minf;
c[t][pre[t]]
+= minf;
t
= pre[t];
}
}
printf(
"%d\n", maxFlow);
}
int main()
{
int i, j, a, b, d, f, N, F, D;
scanf(
"%d%d%d", &N, &F, &D);
S
= 0;
T
= 2 * N + F + D + 1;
memset(c,
0, sizeof(c));
for (i = 1; i <= F; i++){
c[
0][2 * N + i] = 1;
}
for (i = 1; i <= D; i++){
c[
2 * N + F + i][T] = 1;
}
for (i = 1; i <= N; i++){
scanf(
"%d%d", &f, &d);
for (j = 1; j <= f; j++){
scanf(
"%d", &a);
c[
2 * N + a][N + i] = 1;
}
     c[N + i][i] = 1;
for (j = 1; j <= d; j++){
scanf(
"%d", &b);
c[i][
2 * N + F + b] = 1;
}
}
EK();
//system("pause");
return 0;
}

昨天刚看dinic,熟悉一下代码,又写了一个dinic的,用的单路增广dfs:0ms

代码
#include<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#define INF 0xfffffff
#define MM 60500
#define NN 410

int S, T, idx;

typedef
struct node{
int v, wt;
struct node *nxt;
}NODE;
NODE edg[MM];
NODE
*link[NN];

int h[NN];
int que[NN];
int Min(int a, int b){
return a < b ? a : b;
}
void add(int u, int v, int x, int y){
edg[idx].v
= v;
edg[idx].wt
= x;
edg[idx].nxt
= link[u];
link[u]
= edg + idx;
idx
++;

edg[idx].v
= u;
edg[idx].wt
= y;
edg[idx].nxt
= link[v];
link[v]
= edg + idx;
idx
++;
}

int bfs()
{
int u, v, w, tail, head;
memset(h,
-1, sizeof(h));
que[
0] = S;
h[S]
= 0;
tail
= head = 0;
while (head <= tail){
u
= que[head++];
for (NODE *p = link[u]; p; p = p->nxt){
v
= p->v;
w
= p->wt;
if (h[v] == -1 && w > 0){
h[v]
= h[u] + 1;
que[
++tail] = v;
}
}
}
return h[T] != -1;
}

int dfs(int u, int flow){
if (u == T){
return flow;
}
int tmpf = 0;
int v, w, f;
for (NODE *p = link[u]; p; p = p->nxt){
v
= p->v;
w
= p->wt;
if (h[v] == h[u] + 1 && w && tmpf < flow &&(f = dfs(v, Min(w, flow - tmpf)))){
p
->wt -= f;
int t = p - edg;
if (t % 2 == 0){
edg[t
+1].wt += f;
}
else{
edg[t
-1].wt += f;
}
tmpf
+= f;
}
}
if (tmpf == 0) h[u] = -1;
return tmpf;
}
void dinic()
{
int ans = 0;
while(bfs()){
ans
+= dfs(S, INF);
}
printf(
"%d\n", ans);
}

int main()
{
int i, j, a, b, d, f, N, F, D;
scanf(
"%d%d%d", &N, &F, &D);
S
= 0;
T
= 2 * N + F + D + 1;
idx
= 0;
for (i = S; i <= T; i++) link[i] = 0;
for (i = 1; i <= F; i++){
add(
0, 2 * N + i, 1, 0);
}
for (i = 1; i <= D; i++){
add(
2 * N + F + i, T, 1, 0);
}
for (i = 1; i <= N; i++){
scanf(
"%d%d", &f, &d);
for (j = 1; j <= f; j++){
scanf(
"%d", &a);
add(
2 * N + a, N + i, 1, 0);
}
//刚开始把这个写到里面去了,用EK的时候邻接矩阵存的,没影响,
//后来用了dinic,邻接表一存,多加了好多遍,WA了好多次
add(N + i, i, 1, 0);
for (j = 1; j <= d; j++){
scanf(
"%d", &b);
add(i,
2 * N + F + b, 1, 0);
}
}
dinic();
return 0;
}

正在学sap,就找了道题练了练,发现sap如果用递归形式写,真是太简单了。得感谢大牛:zkw

poj1459 Power Network

代码
#include<string.h>
#include
<stdio.h>
#define INF 0xfffffff
#define MM 20500
#define NN 110
int S, T, idx;

typedef
struct node{
int v, wt;
struct node *nxt;
}NODE;

NODE edg[MM];
NODE
*link[NN];
int h[NN];
int que[NN];
int num[NN];
int Min(int a, int b){
return a < b ? a : b;
}

/*加出边邻接表*/
void add(int u, int v, int x, int y){
/*正向加边*/
edg[idx].v
= v;
edg[idx].wt
= x;
edg[idx].nxt
= link[u];
link[u]
= edg + idx++;
/*反向加边*/
edg[idx].v
= u;
edg[idx].wt
= y;
edg[idx].nxt
= link[v];
link[v]
= edg + idx++;
}
int dfs(int u, int flow){
if (u == T){
return flow;
}
int v, w, f;
int tmp = T;
int tf = flow;
for (NODE *p = link[u]; p; p = p->nxt){
v
= p->v;
w
= p->wt;
if (h[u] == h[v] + 1 && w){
f
= dfs(v, Min(w, tf));
tf
-= f;
p
->wt -= f;
int t = p - edg;
if (t % 2 == 0){
edg[t
+1].wt += f;
}
else{
edg[t
-1].wt += f;
}
if (!tf || h[S] == T + 1) return flow - tf;
}

// 这里要取的是《有剩余容量的边中》的距离标号的最小值
if (h[v] < tmp && p->wt > 0) tmp = h[v];

}

if (!(--num[h[u]])) h[S] = T + 1;
else num[h[u] = tmp + 1]++;
return flow - tf;
}
void sap()
{
int ans = 0;
while (h[S] < T + 1){
ans
+= dfs(S, INF);
}
printf(
"%d\n", ans);
}
int main()
{
int n, np, nc, m, a, b, d;
while (scanf("%d%d%d%d", &n, &np, &nc, &m) != EOF){
S
= n; //构造一个源点
T = n + 1;//构造一个汇点
idx = 0;
memset(link,
0, sizeof(link));
while (m--){
scanf(
" (%d,%d)%d", &a, &b, &d);
if (a == b) continue;
add(a, b, d,
0);
}
while (np--){
scanf(
" (%d)%d", &a, &d);
add(S, a, d,
0);
}
while (nc--){
scanf(
" (%d)%d", &a, &d);
add(a, T, d,
0);
}
memset(h,
0, sizeof(h));
memset(num,
0, sizeof(num));
sap();
}
return 0;
}

 

posted on 2010-07-28 21:42  ylfdrib  阅读(757)  评论(0编辑  收藏  举报