POJ 1112(染色+连通分量+DP)

这是一道综合的好题!

题目大意:把n个人分成2各组,每一个人有他所认识的人。所分的组有四点要求:

1、 每个人都必需属于一个组。

2、 每个组至少有一个人。

3、 每个组里面的每个人必需互相认识。

4、 两个组的成员应尽量接近。

首先分析这道题目,题目给出的是一个有向图,即如果有A认识B,但不一定有B认识A。但是在所分配的组里面,任意两个人都要互相认识。

1、 先读入数据建立有向图,然后对这个有向图进行处理,如果两个点之间的边是单向边,就认为两个点之间无边(因为这两个人不互相认识),对于两个点间的双向边,即建立一条无向边(这两个人互相认识),这样就可以把一个有向图转化为一个无向图。

2、 将这个无向图转化为它的反图。即有边的把边删去,无边的添上一条边。(其实1,2步在程序实现时可以一次完成)。

3、 对转换后的反图求极大连通分量。想想就会明白刚才为什么要求反图,可以看到在这个反图中的不同的连通分量中的两个人都是互相认识的!!!接下来很关键,那些互不认识的人就在一个连通分量里面。

4、 在做DFS求连通分量的时候,同时对连通分量中的点染色(0或1),如果一个点颜色为0,那么所有和它相邻的点与它的颜色应该不同(标记为1)。这是因为反图中相邻的两个人都是不认识的(回顾刚才反图的作用)。这样DFS结束后,就可以根据颜色把连通分量中的点分成两个组s0和s1,在不同两个组的人是不可能分到一个team内的。到这里要做一个特判,对于s0或s1组里的任意两个人p,q如果反图中存在一条边(p,q),说明无解,输出"No solution"。

5、 求出了所有的连通分量,对于第i个连通分量都把其节点分为两个组s1i和s2i。这时要做的就是把所有的s1i和s2i分配到team1和team2中去,使team1的总和与team2的总和差值最小。就可以用背包DP了。
dp[i][j]表示第i个连通分量达到j的差值,true为可达,false为不可达。
状态转移方程:
dp[i][j+si0-si1]=true if dp[i-1][j] == true
dp[i][j-si0+si1]=true if dp[i-1][j] == true
同时记录转移路径,差值j的范围是-100~+100可以坐标平移。
最后在dp[m][i](m是最后一个连通块数)中找出值为true的最小i值。输出答案。

 

以上内容转自:http://www.cppblog.com/linyangfei/archive/2008/08/08/58295.html

posted @ 2012-08-28 23:16  proverbs  阅读(356)  评论(0编辑  收藏  举报