`

【最大流+Dinic+Edmonds_Karp+二分匹配】北大 poj 1698 Alice's Chance

阅读更多

Dinic 算法

 

/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
    Copyright (c) 2011 panyanyany All rights reserved.

    URL   : http://poj.org/problem?id=1698
    Name  : 1698 Alice's Chance

    Date  : Wednesday, February 01, 2012
    Time Stage : many hours

    Result: 
9763175	panyanyany
1698
Accepted	404K	16MS	C++
4085B	2012-02-01 19:22:35

Test Data :

Review :
传说是最快的最大流算法,果然名不虚传啊!如果看不懂的,建议先看看这篇文章:
王欣上《浅谈基于分层思想的网络流算法》.doc

然后,一开始看的大牛的解题报告:
http://www.cnblogs.com/littlex/archive/2011/08/17/2142766.html
没有注释很伤心啊,于是我的这个注了很多释,希望以后的同学能看明白~~
//----------------------------------------------------------------------------*/

#include <cstdio>
#include <CSTRING>

using namespace std ;

#define MEM(a, v)		memset (a, v, sizeof (a))	// a for address, v for value
#define max(x, y)		((x) > (y) ? (x) : (y))
#define min(x, y)		((x) < (y) ? (x) : (y))

#define INF		(0x3f3f3f3f)
#define MAXN	401
#define MAXE	16000

struct EDGE {
	int u, v, c, n ;
};

int		n, m, eCnt ;
int		map[MAXN][MAXN], dist[MAXN], vertex[MAXN], q[MAXN] ;

EDGE	edge[MAXE] ;

void init ()
{
	eCnt = 0 ;
	MEM (vertex, -1) ;
}

void insert (int u, int v, int c)
{
	edge[eCnt].u = u ;
	edge[eCnt].v = v ;
	edge[eCnt].c = c ;
	edge[eCnt].n = vertex[u] ;
	vertex[u] = eCnt++ ;

	edge[eCnt].u = v ;
	edge[eCnt].v = u ;
	edge[eCnt].c = 0 ;		// 一开始这里是赋值的 c ,结果很悲剧~~
	edge[eCnt].n = vertex[v] ;
	vertex[v] = eCnt++ ;
}

int dinic (int beg, int end)
{
	int ans = 0 ;
	while (true)
	{
		int head, tail, u, v, e ;

		MEM(dist, -1) ;
		head = tail = 0 ;
		q[tail++] = beg ;
		dist[beg] = 0 ;

		// 广搜,构建层次图
		while (head < tail)
		{
			v = q[head++] ;
			for (e = vertex[v] ; e != -1 ; e = edge[e].n)
			{
				u = edge[e].u ;
				int to = edge[e].v ;
				int cost = edge[e].c ;
				if (cost > 0 && dist[to] == -1)
				{
					dist[to] = dist[u] + 1 ;
					q[tail++] = to ;
					if (to == end)
					{
						head = tail ;
						break ;
					}
				}
			}
		}
		if (dist[end] == -1)
			break ;
		// v 表示增广路径的先头顶点
		v = beg ;
		tail = 0 ;
		while (true)
		{
//			printf("--- tail:%d ", tail) ;
			if (v == end)
			{
				int i, flow = INF, ebreak ;
				// 寻找此路径可增加的最大流量
				for (i = 0 ; i < tail ; ++i)
					if (flow > edge[q[i]].c)
					{
						flow = edge[q[i]].c ;
						ebreak = i ;
					}
				ans += flow ;
				// 根据刚才找到的最大流,更新此路径上的所有边
				for (i = 0 ; i < tail ; ++i)
				{
					edge[q[i]].c -= flow ;		// 正向边减流
					edge[q[i]^1].c += flow ;	// 反向边加流
				}
				// 增广路径的先头顶点退至0流量的正向边的起始顶点
				v = edge[q[ebreak]].u ;
				tail = ebreak ;
//				printf ("end --- v:%d ebreak:%d, ans:%d\n", v, ebreak, ans) ;
			}
			// 寻找有无可以继续增广的边
			// 即,测试所有从顶点 v 起始的边中,是否有可以增广的边
			// find a way from e to any vertex in "layers"
			for (e = vertex[v] ; e != -1 ; e = edge[e].n)
			{
				// 为了避免 -1 + 1 == 0 的情况,需要测试 dist[edge[e].u] > -1
				// 其实这一步貌似可以省略,因为既然能够作为增广路径的先头顶点,
				// 其必然就在层次图中,因此 dist[u] 也就一定会 大于 -1 
				if (edge[e].c > 0 && //dist[edge[e].u] > -1 &&
					dist[edge[e].u]+1 == dist[edge[e].v])
				{
//					printf ("dist[%d]+1 == dist[%d]: %d+1 == %d\n", 
//						edge[e].u, edge[e].v, dist[edge[e].u], dist[edge[e].v]) ;
					break ;
				}
			}
//			printf ("v:%d, e:%d, edge[%d]: u:%d, v:%d, c:%d, n:%d\n",
//				v, e, e, edge[e].u, edge[e].v, edge[e].c, edge[e].n) ;
//			system ("pause 1>>nul 2>>nul") ;

			// 不能从 vertex[v] 所指向的边找到增广路
			if (e == -1)	// no way from current edge's next vertex
			{
				// 路径队列中已经没有边了
				if (tail == 0)	// no edges in queue
					break ;
				// 既然 vertex[v] 所指向的边已经无路可通了
				// 那么就应该把该边的目的顶点从层次图中删除
				// 一开始写成了 dist[edge[q[--tail]].u] = -1
				// 结果一直死循环……本程序所有的注释代码,都是为此错误服务的……
				dist[edge[q[--tail]].v] = -1 ;
				// 增广路径退一条边,回到 vertex[v] 所在边的前一个顶点
				v = edge[q[tail]].u ;	// backward to previous vertex
//				printf ("e == -1 ----- v:%d, tail:%d\n", v, tail) ;
			}
			else			// put the edge in queue
			{
				// 发现一条边可用,于是加入到增广路径队列中
				q[tail++] = e ;
				// 将新边的目的顶点设为增广路径的先头顶点
				v = edge[e].v ;
			}
//			puts ("") ;
		}
	}
	return ans ;
}

int main ()
{
	int i, j, k ;
	int tcase, D, W, days[8], maxW, des, sum ;
	while (scanf ("%d", &tcase) != EOF)
	{
		while (tcase--)
		{
			init () ;
			maxW = sum = 0 ;
			scanf ("%d", &n) ;
			for (i = 1 ; i <= n ; ++i)
			{
				for (j = 1 ; j <= 7 ; ++j)
					scanf ("%d", &days[j]) ;
				scanf ("%d%d", &D, &W) ;
				maxW = max(maxW, W) ;
				sum += D ;

				insert (0, i, D) ;	// edges for each films

				// edges from film to days
				for (j = 0 ; j < W ; ++j)
					for (k = 1 ; k <= 7 ; ++k)
					{
						if (days[k])
						{
							insert(i, j*7+k+n, 1) ;
						}
					}
			}
			// edges from every day to destination
			des = maxW*7+n+1 ;
			for (i = n + 1 ; i < des ; ++i)
				insert(i, des, 1) ;

			int ans = dinic (0, des) ;
			puts (ans == sum ? "Yes" : "No") ;
		}
	}
	return 0 ;
}
 

Edmonds_Karp 解法

 

/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
    Copyright (c) 2011 panyanyany All rights reserved.
 
    URL   : http://poj.org/problem?id=1698
    Name  : 1698 Alice's Chance
 
    Date  : Saturday, January 28, 2012
    Time Stage : Many hours
 
    Result:
9749311
panyanyany
1698
Accepted
804K
860MS
C++
2637B
2012-01-28 13:52:50
 
Test Data :
 
Review :
一开始 end 是400,cnt是401,直接TLE。
//----------------------------------------------------------------------------*/
 
#include <cstdio>
#include <CSTRING>
 
#include <queue>
#include <algorithm>
#include <vector>
 
using namespace std ;
 
#define MEM(a, v)           memset (a, v, sizeof (a))    // a for address, v for value
#define max(x, y)              ((x) > (y) ? (x) : (y))
#define min(x, y)              ((x) < (y) ? (x) : (y))
 
#define INF        (0x3f3f3f3f)
#define MAXN  401
 
#define D     8
#define W    9
 
int          n, m ;
int          flow[MAXN], map[MAXN][MAXN], pre[MAXN] ;
 
int Mark_Point (int beg, int end, int cnt)
{
       int i, t ;
       queue<int> q ;
 
       MEM (pre, -1) ;
 
       flow[beg] = INF ;
       pre[beg] = 0 ;
       q.push (beg) ;
 
       while (!q.empty ())
       {
              t = q.front () ;
              q.pop () ;
 
              if (t == end)
                     break ;
 
              for (i = 0 ; i < cnt ; ++i)
              {
                     if (pre[i] == -1 && map[t][i])
                     {
//                          printf ("%d-->%d ", t, i) ;
                            pre[i] = t ;
                            flow[i] = min (flow[t], map[t][i]) ;
                            q.push (i) ;
                     }
              }
       }
 
       if (pre[end] == -1)
              return -1 ;
       return flow[end] ;
}
 
int Edmonds_Karp (int beg, int end, int cnt)
{
       int incr, step, curr, prev ;
 
       incr = 0 ;
       while ((step = Mark_Point (beg, end, cnt)) != -1)
       {
              incr += step ;
 
              curr = end ;
              while (curr != beg)
              {
                     prev = pre[curr] ;
                     map[prev][curr] -= step ;
                     map[curr][prev] += step ;
                     curr = prev ;
              }
       }
 
       return incr ;
}
 
int main ()
{
       int i, j, k ;
       int tcase, sum, maxday ;
       int w[10] ;
       while (scanf ("%d", &tcase) != EOF)
       {
              while (tcase--)
              {
                     scanf ("%d", &n) ;
                     MEM (map, 0) ;
                     sum = maxday = 0 ;
                     for (i = 1 ; i <= n ; ++i)
                     {
//                          MEM (w, 0) ;
                            for (j = 1 ; j <= 9 ; ++j)
                                   scanf ("%d", &w[j]) ;
 
                            sum += w[D] ;
                            map[0][i] = w[D] ;
                            maxday = max (maxday, w[W]) ;
 
                            for (j = 0 ; j < w[W] ; ++j)
                            {
                                   for (k = 1 ; k <= 7 ; ++k)
                                   {
                                          map[i][k+j*7+n] = w[k] ;
//                                        printf ("%d-->%d == %d , ", i, k+j*7+20, w[k]) ;
//                                        map[k+j*7+20][400] |= w[k] ;
//                                        maxd = max (maxd, k+j*7+20) ;
                                   }
                            }
                     }
                     maxday *= 7 ;
                     for (i = n + 1 ; i <= maxday + n ; ++i)
                            map[i][maxday+1+n] = 1 ;
                    
//                   printf ("\n----%d \n", Edmonds_Karp (0, maxday+1+n, maxday+2+n)) ;
 
                     if (Edmonds_Karp (0, maxday+1+n, maxday+2+n) == sum)
                            puts ("Yes") ;
                     else
                            puts ("No") ;
 
              }
       }
       return 0 ;
}
 

二分图解法

 

/* THE PROGRAM IS MADE BY PYY */
/*----------------------------------------------------------------------------//
    Copyright (c) 2011 panyanyany All rights reserved.
 
    URL   : http://poj.org/problem?id=1698
    Name  : 1698 Alice's Chance
 
    Date  : Saturday, January 28, 2012
    Time Stage : Many hours
 
    Result:
9748843
panyanyany
1698
Accepted
1892K
266MS
C++
1798B
2012-01-28 10:43:31
 
Test Data :
 
Review :
网络流 dinic 算法还不会,先用二分图来做……
参考了一下解题报告:
http://blog.csdn.net/zxy_snow/article/details/6242668
//----------------------------------------------------------------------------*/
 
#include <cstdio>
#include <CSTRING>
 
#include <queue>
#include <algorithm>
#include <vector>
 
using namespace std ;
 
#define MEM(a, v)           memset (a, v, sizeof (a))    // a for address, v for value
#define max(x, y)              ((x) > (y) ? (x) : (y))
#define min(x, y)              ((x) < (y) ? (x) : (y))
 
#define INF        (0x3f3f3f3f)
#define MAXN  401
 
bool       cover[MAXN] ;
 
int          n, m, film_day ;
int          map[1100][MAXN], w[10], link[MAXN] ;
 
int find (int cur)
{
       int i ;
 
       for (i = 1 ; i <= m ; ++i)
       {
              if (cover[i] == false && map[cur][i])
              {
                     cover[i] = true ;
                     if (!link[i] || find (link[i]))
                     {
                            link[i] = cur ;
                            return true ;
                     }
              }
       }
       return false ;
}
 
int main ()
{
       int i, j, k, l ;
       int tcase, sum ;
       scanf ("%d", &tcase) ;
       while (tcase--)
       {
              MEM (map, 0) ;
              m = 0 ;
              scanf ("%d", &n) ;
              film_day = 0 ;
              for (i = 1 ; i <= n ; ++i)
              {
                     for (j = 1 ; j <= 9 ; ++j)
                     {
                            scanf ("%d", &w[j]) ;
                     }
                     for (l = film_day + 1 ; l <= film_day + w[8] ; ++l)
                     {
                            for (j = 0 ; j < w[9] ; ++j)
                            {
                                   for (k = 1 ; k <= 7 ; ++k)
                                   {
                                          map[l][k+j*7] = w[k] ;
                                          m = max (m, k+j*7) ;
                                   }
                            }
                     }
                     film_day += w[8] ;
              }
              sum = 0 ;
              MEM (link, 0) ;
              for (i = 1 ; i <= film_day ; ++i)
              {
                     MEM (cover, 0) ;
                     sum += find (i) ;
              }
              printf ("%s\n", sum == film_day ? "Yes" : "No") ;
       }
       return 0 ;
}
 


0
1
分享到:
评论

相关推荐

    POJ2195-Going Home【费用流】

    【标题】"POJ2195-Going Home" 是一道来自北京大学在线判题系统POJ的编程题目,主要考察的是运用费用流算法解决实际问题的能力。这道题的中文名称是“回家”,通过题目我们可以推测它可能涉及到路径规划或者资源分配...

    最大流题解1

    - POJ3281中,奶牛饮食问题看似复杂,实际上可以通过构建源点到每种食物,每只奶牛到每种饮料,以及奶牛之间的边,将问题转化为多个二分匹配问题的串联,从而用最大流算法解决。 总的来说,最大流问题是一个强大的...

    SNS单模无芯光纤仿真与传感器结构特性分析——基于Rsoft beamprop模块

    内容概要:本文主要探讨了SNS单模无芯光纤的仿真分析及其在通信和传感领域的应用潜力。首先介绍了模间干涉仿真的重要性,利用Rsoft beamprop模块模拟不同模式光在光纤中的传播情况,进而分析光纤的传输性能和模式特性。接着讨论了光纤传输特性的仿真,包括损耗、色散和模式耦合等参数的评估。随后,文章分析了光纤的结构特性,如折射率分布、包层和纤芯直径对性能的影响,并探讨了镀膜技术对光纤性能的提升作用。最后,进行了变形仿真分析,研究外部因素导致的光纤变形对其性能的影响。通过这些分析,为优化光纤设计提供了理论依据。 适合人群:从事光纤通信、光学工程及相关领域的研究人员和技术人员。 使用场景及目标:适用于需要深入了解SNS单模无芯光纤特性和优化设计的研究项目,旨在提高光纤性能并拓展其应用场景。 其他说明:本文不仅提供了详细的仿真方法和技术细节,还对未来的发展方向进行了展望,强调了SNS单模无芯光纤在未来通信和传感领域的重要地位。

    发那科USM通讯程序socket-rece

    发那科USM通讯程序socket-set

    嵌入式八股文面试题库资料知识宝典-WIFI.zip

    嵌入式八股文面试题库资料知识宝典-WIFI.zip

    JS+HTML源码与image

    源码与image

    物流行业车辆路径优化:基于遗传算法和其他优化算法的MATLAB实现及应用

    内容概要:本文详细探讨了物流行业中路径规划与车辆路径优化(VRP)的问题,特别是针对冷链物流、带时间窗的车辆路径优化(VRPTW)、考虑充电桩的车辆路径优化(EVRP)以及多配送中心情况下的路径优化。文中不仅介绍了遗传算法、蚁群算法、粒子群算法等多种优化算法的理论背景,还提供了完整的MATLAB代码及注释,帮助读者理解这些算法的具体实现。此外,文章还讨论了如何通过MATLAB处理大量数据和复杂计算,以得出最优的路径方案。 适合人群:从事物流行业的研究人员和技术人员,尤其是对路径优化感兴趣的开发者和工程师。 使用场景及目标:适用于需要优化车辆路径的企业和个人,旨在提高配送效率、降低成本、确保按时交付货物。通过学习本文提供的算法和代码,读者可以在实际工作中应用这些优化方法,提升物流系统的性能。 其他说明:为了更好地理解和应用这些算法,建议读者参考相关文献和教程进行深入学习。同时,实际应用中还需根据具体情况进行参数调整和优化。

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_8.doc.zip

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_8.doc.zip

    基于灰狼优化算法的城市路径规划Matlab实现——解决TSP问题

    内容概要:本文介绍了基于灰狼优化算法(GWO)的城市路径规划优化问题(TSP),并通过Matlab实现了该算法。文章详细解释了GWO算法的工作原理,包括寻找猎物、围捕猎物和攻击猎物三个阶段,并提供了具体的代码示例。通过不断迭代优化路径,最终得到最优的城市路径规划方案。与传统TSP求解方法相比,GWO算法具有更好的全局搜索能力和较快的收敛速度,适用于复杂的城市环境。尽管如此,算法在面对大量城市节点时仍面临运算时间和参数设置的挑战。 适合人群:对路径规划、优化算法感兴趣的科研人员、学生以及从事交通规划的专业人士。 使用场景及目标:①研究和开发高效的路径规划算法;②优化城市交通系统,提升出行效率;③探索人工智能在交通领域的应用。 其他说明:文中提到的代码可以作为学习和研究的基础,但实际应用中需要根据具体情况调整算法参数和优化策略。

    嵌入式八股文面试题库资料知识宝典-Intel3.zip

    嵌入式八股文面试题库资料知识宝典-Intel3.zip

    嵌入式八股文面试题库资料知识宝典-2019京东C++.zip

    嵌入式八股文面试题库资料知识宝典-2019京东C++.zip

    嵌入式八股文面试题库资料知识宝典-北京光桥科技有限公司面试题.zip

    嵌入式八股文面试题库资料知识宝典-北京光桥科技有限公司面试题.zip

    物理学领域十字形声子晶体的能带与传输特性研究及应用

    内容概要:本文详细探讨了十字形声子晶体的能带结构和传输特性。首先介绍了声子晶体作为新型周期性结构在物理学和工程学中的重要地位,特别是十字形声子晶体的独特结构特点。接着从散射体的形状、大小、排列周期等方面分析了其对能带结构的影响,并通过理论计算和仿真获得了能带图。随后讨论了十字形声子晶体的传输特性,即它对声波的调控能力,包括传播速度、模式和能量分布的变化。最后通过大量实验和仿真验证了理论分析的正确性,并得出结论指出散射体的材料、形状和排列方式对其性能有重大影响。 适合人群:从事物理学、材料科学、声学等相关领域的研究人员和技术人员。 使用场景及目标:适用于希望深入了解声子晶体尤其是十字形声子晶体能带与传输特性的科研工作者,旨在为相关领域的创新和发展提供理论支持和技术指导。 其他说明:文中还对未来的研究方向进行了展望,强调了声子晶体在未来多个领域的潜在应用价值。

    嵌入式系统开发_USB主机控制器_Arduino兼容开源硬件_基于Mega32U4和MAX3421E芯片的USB设备扩展开发板_支持多种USB外设接入与控制的通用型嵌入式开发平台_.zip

    嵌入式系统开发_USB主机控制器_Arduino兼容开源硬件_基于Mega32U4和MAX3421E芯片的USB设备扩展开发板_支持多种USB外设接入与控制的通用型嵌入式开发平台_

    e2b8a-main.zip

    e2b8a-main.zip

    少儿编程scratch项目源代码文件案例素材-火柴人跑酷(2).zip

    少儿编程scratch项目源代码文件案例素材-火柴人跑酷(2).zip

    【HarmonyOS分布式技术】远程启动子系统详解:跨设备无缝启动与智能协同的应用场景及未来展望

    内容概要:本文详细介绍了HarmonyOS分布式远程启动子系统,该系统作为HarmonyOS的重要组成部分,旨在打破设备间的界限,实现跨设备无缝启动、智能设备选择和数据同步与连续性等功能。通过分布式软总线和分布式数据管理技术,它能够快速、稳定地实现设备间的通信和数据同步,为用户提供便捷的操作体验。文章还探讨了该系统在智能家居、智能办公和教育等领域的应用场景,展示了其在提升效率和用户体验方面的巨大潜力。最后,文章展望了该系统的未来发展,强调其在技术优化和应用场景拓展上的无限可能性。 适合人群:对HarmonyOS及其分布式技术感兴趣的用户、开发者和行业从业者。 使用场景及目标:①理解HarmonyOS分布式远程启动子系统的工作原理和技术细节;②探索该系统在智能家居、智能办公和教育等领域的具体应用场景;③了解该系统为开发者提供的开发优势和实践要点。 其他说明:本文不仅介绍了HarmonyOS分布式远程启动子系统的核心技术和应用场景,还展望了其未来的发展方向。通过阅读本文,用户可以全面了解该系统如何通过技术创新提升设备间的协同能力和用户体验,为智能生活带来新的变革。

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_1.zip

    嵌入式八股文面试题库资料知识宝典-C and C++ normal interview_1.zip

    少儿编程scratch项目源代码文件案例素材-激光反弹.zip

    少儿编程scratch项目源代码文件案例素材-激光反弹.zip

    COMSOL相控阵检测技术在有机玻璃斜楔中检测工件内部缺陷的应用研究

    内容概要:本文详细介绍了COMSOL相控阵检测技术在有机玻璃斜楔上放置16阵元进行工件内部缺陷检测的方法。首先阐述了相控阵检测技术的基本原理,特别是通过控制各阵元的激发时间和相位来实现声波的聚焦和扫描。接着,重点解析了横孔缺陷的反射接收波,解释了波的折射现象及其背后的物理原因。最后,通过实例展示了COMSOL模拟声波传播过程的成功应用,验证了该技术的有效性和准确性。 适合人群:从事固体力学、无损检测领域的研究人员和技术人员,尤其是对相控阵检测技术和COMSOL仿真感兴趣的读者。 使用场景及目标:适用于需要精确检测工件内部缺陷的研究和工业应用场景,旨在提高检测精度和效率,确保产品质量和安全。 其他说明:文中提到的声速匹配现象有助于理解波在不同介质间的传播特性,这对优化检测参数设置有重要意义。

Global site tag (gtag.js) - Google Analytics