HDU 4289 Control(拆点,最大流)

来源:互联网 发布:Ubuntu进程的创建命令 编辑:程序博客网 时间:2024/06/02 09:22
/*拆点:将每一个节点拆为a,a1,边的权值给节点的最小消耗,如果节点a、b之间原来有边相连,则a1,b和b1,a之间连接两条边,权值为INF。于是转换为最大流问题新收获:我原来打算用vector存储邻接表,最后发现反向遍无法处理。终于明白了②、③处的用法,目的方便对反向遍进行运算。异或使两边对应起来*///dinic实现#include <cstdio>#include <cstring>#include <vector>#include <queue>using namespace std;const int nMax = 407;const int mMax = 200000;const int INF = 0x3fffffff;struct Adj{int v, w;int next;}adj[nMax + mMax];//②int head[nMax];int cnt;int N, M, S, D;int dis[nMax];void addEdge(int u, int v, int w){adj[cnt].v = v;adj[cnt].w = w;adj[cnt].next = head[u];head[u] = cnt ++;adj[cnt].v = u;adj[cnt].w = 0;adj[cnt].next = head[v];head[v] = cnt ++;}int bfs(int s, int d){queue<int> que;que.push(s);memset(dis, -1, sizeof(dis));dis[s] = 0;int i;while(!que.empty()){int u = que.front();que.pop();for(i = head[u]; i != -1; i = adj[i].next){int v = adj[i].v;if(adj[i].w && dis[v] == -1){dis[v] = dis[u] + 1;que.push(v);}}}return dis[d];}int min(int a, int b){return a < b ? a : b;}int dfs(int s, int d, int cost){if(s == d) return cost;int t, ans = 0;int i;for(i = head[s]; i != -1; i = adj[i].next){int v = adj[i].v;if(dis[v] == dis[s] + 1 && adj[i].w && (t = dfs(v, d, min(adj[i].w, cost))) != -1)//①原来这里漏写了adj[i].w != 0,结果超时{adj[i].w -= t;adj[i ^ 1].w += t;//③cost -= t;ans += t;if(!cost) break;}}return ans;}int dinic(int s, int d){int ans = 0;while(bfs(s, d) != -1){ans += dfs(s, d, INF);}return ans;}int main(){//freopen("e://data.in", "r",stdin);while(scanf("%d%d%d%d", &N, &M, &S, &D) != EOF){int i;int a, b;memset(head, -1, sizeof(head));cnt = 0;for(i = 1; i <= N; ++ i){scanf("%d", &a);addEdge(i, i + N, a);}for(i = 1; i <= M; ++ i){scanf("%d%d", &a, &b);addEdge(a + N, b, INF);addEdge(b + N, a, INF);}int ans = dinic(S, D + N);printf("%d\n", ans);}return 0;}//isap实现#include <cstdio>#include <cstring>#include <vector>#include <queue>using namespace std;const int nMax = 407;const int mMax = 200000;const int INF = 0x3fffffff;struct Adj{int v, w;int next;}adj[nMax + mMax];int head[nMax];int cnt;int num[nMax];int N, M, S, D;int dis[nMax];int NN;void addEdge(int u, int v, int w){adj[cnt].v = v;adj[cnt].w = w;adj[cnt].next = head[u];head[u] = cnt ++;adj[cnt].v = u;adj[cnt].w = 0;adj[cnt].next = head[v];head[v] = cnt ++;}int min(int a, int b){return a < b ? a : b;}int dfs(int u, int s, int d, int cost){if(u == d) return cost;int i;int ans = 0;int _min = NN;for(i = head[u]; i != -1; i = adj[i].next){int v = adj[i].v;if(adj[i].w){if(dis[v] + 1 == dis[u]){int t = dfs(v, s, d, min(adj[i].w, cost));adj[i].w -= t;adj[i ^ 1].w += t;cost -= t;ans += t;if(dis[s] == NN) return ans;if(!cost) break;}if(_min > dis[v])_min = dis[v];}}if(!ans){if(-- num[dis[u]] == 0) dis[s] = NN;dis[u] = _min + 1;++ num[dis[u]];}return ans;}int isap(int s, int d){memset(dis, 0, sizeof(dis));memset(num, 0, sizeof(num));num[0] = NN;int ans = 0;while(dis[s] < NN)ans += dfs(s, s, d, INF);return ans;}int main(){//freopen("e://data.in", "r",stdin);while(scanf("%d%d%d%d", &N, &M, &S, &D) != EOF){NN = 2 * N;int i;int a, b;memset(head, -1, sizeof(head));cnt = 0;for(i = 1; i <= N; ++ i){scanf("%d", &a);addEdge(i, i + N, a);}for(i = 1; i <= M; ++ i){scanf("%d%d", &a, &b);addEdge(a + N, b, INF);addEdge(b + N, a, INF);}int ans = isap(S, D + N);printf("%d\n", ans);}return 0;}

原创粉丝点击