• 洛谷P2050[NOI2012]美食节(网络流+动态加边优化)


    题目:https://www.luogu.org/problemnew/show/P2050

    imageimageimage


    分析:一看见几个厨师同时做就立刻想到了网络流,再一细看和修车那道题挺像的。于是仿照那道题把厨师拆了(-_-||),每个厨师拆成p个点,代表第几个厨师做的倒数第几道菜,然后各自向每一道菜连边,容量为1,费用为j*花费的时间。最后源点向每个厨师拆出来的点连费用为0,容量为1的边;每一道菜向汇点连容量为这道菜出现次数,费用为0的边。跑一遍最小费用最大流就行了。

    然而!!!!!!!!!!!

    image

    通过计(zhi)算(jue),发现此题最多可有3280040条边,算上反向的。。。。。可怕。难怪会T。

    从这里继续想下去,自然想减少边数,但显然每一条边都可能会用到。然后看一眼数据范围,稍一联想,此图最大流必为image,即最大为800,所以最多找800次增广路,图中有很多边没有用到。所以我们先不忙把所有的边都加上,只连下一次找增广路可能会用到的边

    那么对于第一次,源点→每个厨师做的倒数第一道菜→每一道菜→汇点,这些边连上。然后每一次寻找增广路必定会过一个”第i个厨师做的倒数第j道菜”这样的点,我们再连源点→第i个厨师做的倒数第j+1道菜→每一道菜。

    这样一来图中的边就少了很多,应该就能A了!!!!

    然而。。。。。。

    image

    什么鬼????好吧无奈只能手写队列过了。。。。。。

    代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <queue>
      5 using namespace std;
      6 
      7 typedef long long LL;
      8 struct Edge
      9 {
     10 	int v, next, cap, cost;
     11 	Edge(int a = 0, int b = 0, int c = 0, int d = 0)
     12 	:v(a), next(b), cap(c), cost(d){};
     13 }edge[6600001];
     14 int n, m, s, t, cnt, ans, p_tot;
     15 int pre[80050], dist[80050], timeT[42][102], head[80050];
     16 bool inQueue[80050];
     17 int q[80050], headOfQueue, tailOfQueue;
     18 
     19 void AddEdge(int _u, int _v, int _cap, int _cost)
     20 {
     21 	edge[cnt] = Edge(_v, head[_u], _cap, _cost);
     22 	head[_u] = cnt++;
     23 	edge[cnt] = Edge(_u, head[_v], 0, -_cost);
     24 	head[_v] = cnt++;
     25 }
     26 void SPFA()
     27 {
     28 	memset(dist, 0x7f, sizeof(dist));
     29 	dist[s] = 0;
     30 	headOfQueue = tailOfQueue = 0;
     31 	q[tailOfQueue++] = s;
     32 	while(tailOfQueue > headOfQueue)
     33 	{
     34 		int p = q[headOfQueue++];
     35 		inQueue[p] = false;
     36 		for(int i = head[p]; ~i; i = edge[i].next)
     37 			if(edge[i].cap && dist[p] + edge[i].cost < dist[edge[i].v])
     38 			{
     39 				dist[edge[i].v] = dist[p] + edge[i].cost;
     40 				pre[edge[i].v] = i;
     41 				if(!inQueue[edge[i].v])
     42 				{
     43 					inQueue[edge[i].v] = true;
     44 					q[tailOfQueue++] = edge[i].v;
     45 				}
     46 			}
     47 	}
     48 	int p = t, record;
     49 	while(p != s)
     50 	{
     51 		int o = pre[p];
     52 		if(edge[o ^ 1].v == 0) record = p;
     53 		edge[o].cap--;
     54 		edge[o ^ 1].cap++;
     55 		p = edge[o ^ 1].v;
     56 	}
     57 	ans += dist[t];
     58 	record += p_tot - 1;
     59 	int A = record / p_tot, B = record % p_tot + 1;
     60 
     61 	AddEdge(s, (A - 1) * p_tot + B + 1, 1, 0);
     62 	for(int i = 1; i <= n; i++)
     63 		AddEdge((A - 1) * p_tot + B + 1, 80000 + i, 1, (B + 1) * timeT[i][A]);
     64 }
     65 int main()
     66 {
     67 	memset(head, -1, sizeof(head));
     68 	scanf("%d%d", &n, &m);
     69 	s = 0, t = 80041;
     70 	for(int i = 1; i <= n; i++)
     71 	{
     72 		int p;
     73 		scanf("%d", &p);
     74 		AddEdge(80000 + i, t, p, 0);
     75 		p_tot += p;
     76 	}
     77 	for(int i = 1; i <= n; i++)
     78 		for(int j = 1; j <= m; j++)
     79 			scanf("%d", &timeT[i][j]);
     80 	for (int i = 1; i <= m; i++)
     81 	{
     82 		AddEdge(s, (i - 1) * p_tot + 1, 1, 0);
     83 		for(int j = 1; j <= n; j++)
     84 			AddEdge((i - 1) * p_tot + 1, 80000 + j, 1, timeT[j][i]);
     85 	}
     86 	for (int i = 1; i <= p_tot; i++)
     87 		SPFA();
     88 	printf("%d", ans);
     89 
     90 	return 0;
     91 }//Rhein_E
    View Code
  • 相关阅读:
    移动web前端高效开发实践 读书笔记
    前端开发最佳实践-读书笔记
    frontend-Tips
    匿名函数的几种写法
    12个用得着的JQuery代码片段(转)
    tesseract-ocr 学习笔记(比网上的中文说明都详细)
    关于大数据的思考
    单片机实验的小记录~~PWM
    组建Redis集群遇到`GLIBC_2.14' not found和ps -ef 不显示用户名
    柔性数组(Redis源码学习)
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/9297809.html
Copyright © 2020-2023  润新知