[Drainage Ditches]USACO
最大流问题,这题提交了提交了两次,第一次提交时test9输出错误,查了半天才发现数据中有重复的边。仔细看了一下题“ Note however, that there can be more than one ditch between two intersections.”也就是说,两个点之间可以有多条边。把多条边合成一条边就OK了。
用的是relabel to front. 为了方便,代码全部用的数组。
--------------------------------------------
/* ID: zhangyc1 LANG: C++ TASK: ditch */ #include <fstream> #include <iostream> #include <cstdlib> #include <cstring> using namespace std; #define MAX_HEIGHT 1000000 ofstream fileout("ditch.out"); const int NODENUM = 201; int N, M; int arrExtra[NODENUM]; // 预流 int arrCap[NODENUM][NODENUM], arrFlow[NODENUM][NODENUM]; // 容量,当前流量 int arrVisitList[NODENUM], arrHeight[NODENUM], arrVisitPos[NODENUM]; // 节点的处理顺序,节点高度,节点的访问指针 void prepairData() { memset(arrCap, 0, sizeof(arrCap)); memset(arrFlow, 0, sizeof(arrFlow)); memset(arrExtra, 0, sizeof(arrExtra)); memset(arrHeight, 0, sizeof(arrHeight)); ifstream filein("ditch.in"); filein >> N >> M; arrHeight[1] = M; int nFrom, nTo, nCap; for (int i = 0; i < N; i++) { filein >> nFrom >> nTo >> nCap; // 两个点之前可能有多条沟 arrCap[nFrom][nTo] += nCap; } for (int i = 0; i < M - 2; i++) // 设为{2, 3, 4 ... M-1} { arrVisitList[i] = i + 2; } for (int i = 0; i <= M; i++) // 从源点开始 { arrVisitPos[i] = 1; } for (int i = 2; i <= M; i++) { arrFlow[1][i] = arrCap[1][i]; arrFlow[i][1] = -arrFlow[1][i]; arrExtra[i] += arrCap[1][i]; arrExtra[1] -= arrCap[1][i]; } filein.close(); } void PushOperation(int u, int v) { int nMin = min(arrExtra[u], arrCap[u][v] - arrFlow[u][v]); arrExtra[u] -= nMin; arrExtra[v] += nMin; arrFlow[u][v] += nMin; arrFlow[v][u] = -arrFlow[u][v]; } void RelabelOperation(int u) { int nMin = MAX_HEIGHT; for (int v = 1; v <= M; v++) { if (arrCap[u][v] > arrFlow[u][v] && nMin > arrHeight[v]) nMin = arrHeight[v]; } arrHeight[u] = nMin + 1; } void Dicharge(int u) { while(arrExtra[u] > 0) { if (arrVisitPos[u] <= M) { if (arrHeight[u] > arrHeight[arrVisitPos[u]] && arrCap[u][arrVisitPos[u]] > arrFlow[u][arrVisitPos[u]]) { PushOperation(u, arrVisitPos[u]); } else arrVisitPos[u]++; } else { RelabelOperation(u); arrVisitPos[u] = 1; } } } void MoveToFront(int u) { int nKey = arrVisitList[u]; for (int i = u; i > 0; i--) { arrVisitList[i] = arrVisitList[i - 1]; } arrVisitList[0] = nKey; } void RelabelToFront() { int nCurVisit = 0; while (nCurVisit < M - 2) { int u = arrVisitList[nCurVisit]; int oldHeight = arrHeight[u]; Dicharge(u); if (oldHeight != arrHeight[u]) { MoveToFront(nCurVisit); nCurVisit = 1; } else nCurVisit++; } } int main(){ prepairData(); RelabelToFront(); // should be 2763609 fileout << arrExtra[M] << endl; fileout.close(); return 0; }