pku 1149最大流(标号法)

 1 /*

 2 *  一般增广路算法--Ford_Fulkerson算法(标号法) 

 3 */

 4 /*

 5 建图:将顾客看作除源点和汇点以外的节点,源点和每个猪圈的第一个顾客连边,边的权是开始时猪

 6 圈中猪的数目,若源点和某个节点之间有重边,则将权合并,顾客j紧跟在顾客i之后打开某个猪圈,

 7 则边<i,j>的权是+∞,每个顾客和汇之间连边,边的权是顾客所希望购买的猪的数目。

 8 */ 

 9 

10 #include <cstdio>

11 #include <cstring>

12 #include <iostream>

13 

14 using namespace std;

15 

16 const int N = 100;   

17 const int M = 1000;

18 const int INF = 1000000000;

19 

20 int vs, vt;            //源点与汇点 

21 int front, rear;       //队列头与尾 

22 int Q[N+2];            //队列 

23 int prev[N+2];         //标号法的第一个分量 

24 int minflow[N+2];      //标号法的第二个分量 

25 int flow[N+2][N+2];    //节点之间的流量 

26 int customer[N+2][N+2];//节点之间的容量 

27 int house[M];  //存储每个猪圈中猪的数目 

28 int last[M];   //存储每个猪圈的前一个顾客的序号 

29 

30 void buildFlow() {     //建图 

31     int n, m, num, k;

32     memset(last, 0, sizeof(last));

33     memset(customer, 0, sizeof(customer));

34     scanf ("%d%d", &m, &n);

35     vs = 0, vt = n + 1;  //源点与汇点的编号 

36     for (int i=1; i<=m; ++i) scanf ("%d", &house[i]);

37     for (int i=1; i<=n; ++i) {

38         scanf ("%d", &num);

39         for (int j=1; j<=num; ++j) {

40             scanf ("%d", &k);

41             if (last[k] == 0) customer[vs][i] += house[k];//第i个顾客是第k个猪圈的第1个顾客 

42             else customer[last[k]][i] = INF;//表示顾客i紧跟顾客last[k]后面打开第k个猪圈 

43             last[k] = i;

44         }

45         scanf ("%d", &customer[i][vt]);//每个顾客到汇点的边,权值为顾客购买猪的数目 

46     }  

47 }

48 

49 int Ford_Fulkerson() {

50     int v, p;

51     for (int i=0; i<N+2; ++i) {//构造零流,从零流开始标号调整 

52         for (int j=0; j<N+2; ++j) flow[i][j] = 0;

53     }

54     minflow[0] = INF;   //源点标号的第2个分量为无穷大 

55     while (1) {         //标号法,采用BFS的思想遍历网络,从而对所有顶点进行标号 

56         for (int i=0; i<N+2; ++i) prev[i] = -2;//每次标号前,每个顶点重新回到未标号状态 

57         prev[0] = -1;  //源点的标号为-1 

58         front = rear = 0;

59         Q[front++] = 0;

60         while (rear<front && prev[vt]==-2) {//标号过程 

61             v = Q[rear++];

62             for (int i=0; i<vt+1; ++i) {

63                 if (prev[i]==-2 && (p=customer[v][i]-flow[v][i])) {

64                     prev[i] = v;

65                     Q[front++] = i;

66                     minflow[i] = (minflow[v] < p) ? minflow[v] : p;

67                 }

68             }

69         }

70         if (prev[vt] == -2) break;//汇点vt没有标号,标号法结束 

71         int i, j;

72         for (i=prev[vt], j=vt; i!=-1; j=i, i=prev[i]) {//调整过程 

73             flow[i][j] += minflow[vt];

74             flow[j][i] -= minflow[vt];

75         }

76     }

77     p = 0;

78     for (int i=0; i<vt; ++i) p += flow[i][vt];//统计进入汇点的流量,即为最大流的流量 

79     return p; 

80 }

81 

82 int main() {

83     buildFlow();

84     int ans = Ford_Fulkerson();

85     printf ("%d\n", ans);

86     return 0; 

87 }

 

 

你可能感兴趣的:(pku)