zoukankan      html  css  js  c++  java
  • 洛谷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
  • 相关阅读:
    HDU 4472 Count DP题
    HDU 1878 欧拉回路 图论
    CSUST 1503 ZZ买衣服
    HDU 2085 核反应堆
    HDU 1029 Ignatius and the Princess IV
    UVa 11462 Age Sort
    UVa 11384
    UVa 11210
    LA 3401
    解决学一会儿累了的问题
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/9297809.html
Copyright © 2011-2022 走看看