ACM-ICPC 2018 沈阳赛区网络预赛 F. Fantastic Graph(有源上下界最大流 模板)
关于有源上下界最大流: https://blog.csdn.net/regina8023/article/details/45815023
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n, m, k, l, r, s, t, superS, superT; const int MAXN = 5000;//点数的最大值 const int MAXM = 120000;//边数的最大值 const int INF = 0x3f3f3f3f; struct Edge { int to,next,cap,flow; } edge[MAXM]; //注意是MAXM int tol; int head[MAXN]; void init() { tol = 2; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw = 0) { edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0; edge[tol].next = head[u]; head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0; edge[tol].next = head[v]; head[v] = tol++; } int Q[MAXN]; int dep[MAXN],cur[MAXN],sta[MAXN]; bool bfs(int s,int t,int n) { int front = 0,tail = 0; memset(dep,-1,sizeof(dep[0])*(n+1)); dep[s] = 0; Q[tail++] = s; while(front < tail) { int u = Q[front++]; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > edge[i].flow && dep[v] == -1) { dep[v] = dep[u] + 1; if(v == t) return true; Q[tail++] = v; } } } return false; } int dinic(int s,int t,int n) { int maxflow = 0; while(bfs(s,t,n)) { for(int i = 0; i < n; i++) cur[i] = head[i]; int u = s, tail = 0; while(cur[s] != -1) { if(u == t) { int tp = INF; for(int i = tail-1; i >= 0; i--) tp = min(tp,edge[sta[i]].cap-edge[sta[i]].flow); maxflow += tp; for(int i = tail-1; i >= 0; i--) { edge[sta[i]].flow += tp; edge[sta[i]^1].flow -= tp; if(edge[sta[i]].cap-edge[sta[i]].flow == 0) tail = i; } u = edge[sta[tail]^1].to; } else if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) { sta[tail++] = cur[u]; u = edge[cur[u]].to; } else { while(u != s && cur[u] == -1) u = edge[sta[--tail]^1].to; cur[u] = edge[cur[u]].next; } } } return maxflow; } int main() { int kase = 1; while(~scanf("%d %d %d", &m, &n, &k)) { scanf("%d %d", &l, &r); s = n + m + 1; t = n + m + 2; superS = n + m + 3; superT = n + m + 4; init(); for(int i = 1; i <= k; i++) { int u, v; scanf("%d %d", &u , &v); addedge(u, v + n, 1); //二分图 建一条容量为1的边 } addedge(t,s,INF); //从汇点向源点建一条inf的边 for(int i = 1; i <= n; i++){ addedge(s, i, r - l); //从源点向左半图连边 addedge(superS, i, l); addedge(s, superT, l); } for(int i = 1; i <= m; i++){ int aim = i + n; addedge(aim, t, r - l); addedge(aim, superT, l); addedge(superS, t, l); } printf("Case %d: ", kase++); int ans = dinic(superS, superT, n+m+4); if(ans == (n+m)*l) puts("Yes"); else puts("No"); } return 0; }