AbOr's story --FOJ 1980

1、题目类型:图论、最大流、最小切割最大流定理、Dinic算法。

2、解题思路:《算法艺术与信息学竞赛》中只是换了一种说明的原题(P317)。(1)构建二分图G,它的X结点为所有的宝石,每个宝石 i 用 Xi 来表示,连接一条容量为 Ii 的弧S-Yi;它的Y结点为所有的女孩,每个女孩 i 用 Yi 来表示,连接一条容量为Ei的弧Yi-T。(2)最小切割最大流定理(证明),步骤1:最小切割不可能包含无限容量的边。这是显然的,因此如果在T集中的任何一个女孩 Ej 需要宝石 Ij ,那么 Ij 一定也在T集中,它保证了切割一定对应一个可行方案。步骤2:对于任何一个宝石 i ,如果宝石在T集合中,说明该宝石应当购买,这时容量 Ii 被计算在了切割中;对于任何一个女孩 j ,如果女孩在集合T中,说明女孩被选择,这时容量 Ej 并没有计算在切割中,这样,该方案所对应的切割数值等于 sum{Ii}+sum{Ej};(3)若所有女孩的总收益E,最大收益=E-(sum{Ii}+sum{Ej})。

3、注意事项:注意最大流的求解,此题只有Dinic算法符合题意,Ford-Fulkerson算法、SAP算法TLE。

4、实现方法:

  
    
#include < iostream >
#define MAXN 20010
#define MAXM 200000
#define INIFINITY 10000000000
using namespace std;

typedef __int64 FLOW;

struct Edge { // v:adjacent to, r: remains, c: capacity
int v;
FLOW r, c;
Edge
* next; // adjacent list
Edge * Reverse(); // get the pointer of reverse edge
};

struct Vertex {
Edge
* first; // first adjacent edge of the vertex
};

Edge edges[MAXM];
// edges's list
Vertex g[MAXN]; // vertexes's list
int n, m, s, t; // vertex's number, edges's number, source, terminal
int dest; // the vertex ending the dfs process
int d[MAXN]; // the level of the vertex(dinic); the distance to t (SAP)

// get the reference of the reverse edge of it
Edge inline * Edge::Reverse()
{
return edges + (( this - edges) ^ 1 );
}

void AddEdge( int u, int v, FLOW c)
{
// add sigle edge to network
edges[m].v = v;
edges[m].r
= c; // notation: use .r or use .c
edges[m].next = g[u].first;
g[u].first
= edges + m;
m
++ ;
}

void Insert( int u, int v, FLOW c1, FLOW c2)
{
// insert a two-way edge
AddEdge(u, v, c1);
AddEdge(v, u, c2);
}

// bfs to construct the level graph
bool BFS_Dinic( int s, int t, int n)
{
int Q[MAXN]; // queue to construct level graph
int front, rear, u;
for (u = 0 ; u < n; u ++ ) d[u] = n;
front
= rear = 0 ;
Q[rear
++ ] = t;
d[t]
= n - 1 ;
while (front < rear)
{
u
= Q[front ++ ];
for (Edge * p = g[u].first; p; p = p -> next)
{
if (p -> Reverse() -> r > 0 && d[p -> v] == n)
{
d[p
-> v] = d[u] - 1 ;
Q[rear
++ ] = p -> v;
if (p -> v == s) return true ;
}
}
// for*/
} // while
return false ;
}

// sub function of Dinic_DFS
FLOW DFS_Dinic(Edge * e, FLOW flow)
{
FLOW f
= 0 ;
if (e -> r < flow) flow = e -> r;
if (e -> v == dest)
f
= flow;
else
{
for (Edge * p = g[e -> v].first; p && (f < flow); p = p -> next)
{
// f < flow is important
if (p -> r > 0 && d[p -> v] > d[e -> v])
{
// -> d[p->v] == d[e->v] + 1
f += DFS_Dinic(p, flow - f);
}
}
}
e
-> r -= f;
e
-> Reverse() -> r += f;
return f;
}

// main function of dinic algorithm
FLOW Dinic( int s, int t, int n)
{
FLOW maxflow
= 0 ;
Edge
* first = edges + m + 1 ;
first
-> v = s;
dest
= t;
while ( true ) {
first
-> r = INIFINITY;
if ( ! BFS_Dinic(s, t, n)) break ; // t not in residual network
maxflow += DFS_Dinic(first, INIFINITY);
}
return maxflow;
}

int wm,bs;
FLOW sum;

void Init()
{
int i,j,b,c,cnt;
scanf(
" %d%d " , & wm, & bs);
s
= 0 ;m = 0 ;sum = 0 ;
t
= wm + bs + 1 ;n = t + 1 ;
for (i = 0 ;i < n;i ++ )
g[i].first
= NULL;
for (i = 1 ;i <= wm;i ++ )
{
scanf(
" %d " , & cnt);
for (j = 0 ;j < cnt;j ++ )
{
scanf(
" %d " , & b);
Insert(b,i
+ bs,INIFINITY, 0 );
}
scanf(
" %d " , & c);
sum
+= c;
Insert(i
+ bs,t,c, 0 );
}
for (j = 1 ;j <= bs;j ++ )
{
scanf(
" %d " , & c);
Insert(s,j,c,
0 );
}
}

int main()
{
int T, ca = 1 ;
scanf(
" %d " , & T);
while (T -- )
{
Init();
sum
-= Dinic(s,t,n);
printf(
" Case %d: %I64d\n " ,ca ++ ,sum);
}
return 0 ;
}

 

你可能感兴趣的:(ab)