“科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛) - G养花
“科林明伦杯”哈尔滨理工大学第十届程序设计竞赛(同步赛) - G养花
链接:https://ac.nowcoder.com/acm/contest/5758/G
来源:牛客网
题目描述
小明是一个魔法师,他有n棵植物,所有植物排成一排,植物的初始高度为数组h,小明有一些强迫症,他想
让植物的高度都恰好达到k,小明有m瓶药水,但药水分为4种:
1.选择一棵高度为a0的植物变为b0高度的植物
2.选择一棵高度在[a1,a2]区间内的植物变为b1高度的植物
3.选择一棵高度为a1的植物变为[b1, b2]区间内某一高度的植物
4.选择一棵高度在[a1,a2]区间内的植物变为[b1,b2]区间内某一高度的植物
由于每瓶药水有C瓶库存,小明想知道他最多让多少棵植物高度达到k
输入描述:
输入数据第一行是t,表示数据的组数,接下来每组数据输入n,m,k, 接下来一行输入n个数,分别是每棵植物的高度h[i](1 <= h[i] < k), 接下来m行开头的两个数字为op和c表示药水是哪一种和该种药水有几瓶,输入如下 若 op=1,则接下来两个整数 a0,b0,意义如上文所述。 若 op=2,则接下来三个整数 a1,a2,b1,意义如上文所述。 若 op=3,则接下来三个整数 a1,b1,b2,意义如上文所述。 若 op=4,则接下来四个整数 a1,a2,b1,b2,意义如上文所述。 数据保证,所有 1 <= a0,b0,a1,b1,a2,b2 <= k (t <= 10,n <= 1e4,m <= 300,k <= 100,c <=1e6)
输出描述:
输出一个整数,表示最多有多少颗植物能生涨到k。
思路:
算法:流量网络求最大流。
建图方法:
节点代表高度为的花
设节点为源点,为汇点。
用数组记录最初有多少个高度为的花,
源点和每一个高度节点可以建边:代表从指向流量为的单向边。
四种药水也可以根据题意分别建立高度节点和高度节点之间的边。
最后建立高度为的节点与汇点的边,流量设为无穷大。即:
然后求的最大流即可。
样例1的流量网络为:
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #include <sstream> #include <bitset> #include <unordered_map> // #include <bits/stdc++.h> #define ALL(x) (x).begin(), (x).end() #define sz(a) int(a.size()) #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define chu(x) if(DEBUG_Switch) cout<<"["<<#x<<" "<<(x)<<"]"<<endl #define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define du2(a,b) scanf("%d %d",&(a),&(b)) #define du1(a) scanf("%d",&(a)); using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;} ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;} void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}} inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;} void pvarr_int(int *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%d%c", arr[i], i == n ? '\n' : ' ');}} void pvarr_LL(ll *arr, int n, int strat = 1) {if (strat == 0) {n--;} repd(i, strat, n) {printf("%lld%c", arr[i], i == n ? '\n' : ' ');}} const int maxn = 100010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ #define DEBUG_Switch 0 #define N 1500 #define INF 1e13 struct Edge { int from, to; ll cap, flow; // cap 并不减少,只是flow在增,有残余就是cap>flow }; struct ISAP { int n, m, s, t; vector<Edge>edges; vector<int>G[N]; bool vis[N]; int d[N], cur[N]; int p[N], num[N]; //比Dinic算法多了这两个数组,p数组标记父亲结点,num数组标记距离d[i]存在几个 void addedge(int from, int to, ll cap) { // cout << from << " " << to << " " << cap << endl; edges.push_back((Edge) {from, to, cap, 0}); edges.push_back((Edge) {to, from, 0, 0}); int m = edges.size(); G[from].push_back(m - 2); G[to].push_back(m - 1); } void init() { MS0(d); edges.clear(); for (int i = 0; i <= n; ++i) { G[i].clear(); } } ll Augumemt() { ll x = t, a = INF; while (x != s) //找最小的残量值 { Edge&e = edges[p[x]]; a = min(a, e.cap - e.flow); x = edges[p[x]].from; } x = t; while (x != s) //增广 { edges[p[x]].flow += a; edges[p[x] ^ 1].flow -= a; x = edges[p[x]].from; } return a; } void bfs()//逆向进行bfs { memset(vis, 0, sizeof(vis)); queue<int>q; q.push(t); d[t] = 0; vis[t] = 1; while (!q.empty()) { int x = q.front(); q.pop(); int len = G[x].size(); for (int i = 0; i < len; i++) { Edge&e = edges[G[x][i]]; if (!vis[e.from] && e.cap > e.flow) { vis[e.from] = 1; d[e.from] = d[x] + 1; q.push(e.from); } } } } ll Maxflow(int s, int t) //根据情况前进或者后退,走到汇点时增广 { this->s = s; this->t = t; ll flow = 0; bfs(); memset(num, 0, sizeof(num)); for (int i = 0; i < n; i++) num[d[i]]++; int x = s; memset(cur, 0, sizeof(cur)); while (d[s] < n) { if (x == t) //走到了汇点,进行增广 { flow += Augumemt(); x = s; //增广后回到源点 } int ok = 0; for (int i = cur[x]; i < G[x].size(); i++) { Edge&e = edges[G[x][i]]; if (e.cap > e.flow && d[x] == d[e.to] + 1) { ok = 1; p[e.to] = G[x][i]; //记录来的时候走的边,即父边 cur[x] = i; x = e.to; //前进 break; } } if (!ok) //走不动了,撤退 { int m = n - 1; //如果没有弧,那么m+1就是n,即d[i]=n for (int i = 0; i < G[x].size(); i++) { Edge&e = edges[G[x][i]]; if (e.cap > e.flow) m = min(m, d[e.to]); } if (--num[d[x]] == 0)break; //如果走不动了,且这个距离值原来只有一个,那么s-t不连通,这就是所谓的“gap优化” num[d[x] = m + 1]++; cur[x] = 0; if (x != s) x = edges[p[x]].from; //退一步,沿着父边返回 } } return flow; } // 调用前给这里的n赋值,一般为n=T+1; } gao; int n; int m, k; int cnt[maxn]; // bool check(ll mid) // { // gao.init(); // int S = 0; // int T = n + 10; // gao.n = T + 1; // gao.addedge(n + i, T, d[i]); // ll res = gao.Maxflow(S, T); // } int main() { #if DEBUG_Switch freopen("C:\\code\\input.txt", "r", stdin); #endif //freopen("C:\\code\\output.txt","r",stdin); int t; t = readint(); while (t--) { n = readint(); m = readint(); k = readint(); repd(i, 1, k) { cnt[i] = 0; } repd(i, 1, n) { int x = readint(); cnt[x]++; } int S = 0; repd(i, 1, k) { gao.addedge(S, i , cnt[i] ); } int id = k; repd(i, 1, m) { int op = readint(); int c = readint(); if (op == 1) { int a0 = readint(); int b0 = readint(); gao.addedge( a0 , b0, c ); } else if (op == 2) { int a1 = readint(); int a2 = readint(); int b1 = readint(); repd(a0, a1, a2) { gao.addedge( a0, b1, c ); } } else if (op == 3) { int a0 = readint(); int b1 = readint(); int b2 = readint(); repd(b0, b1, b2) { gao.addedge( a0, b0, c ); } } else if (op == 4) { int a1 = readint(); int a2 = readint(); int b1 = readint(); int b2 = readint(); repd(a0, a1, a2) { repd(b0, b1, b2) { gao.addedge( a0, b0, c ); } } } } id++; int T = id ; gao.addedge(k , T, INF ); gao.n = T + 1; ll res = gao.Maxflow(S, T); gao.init(); printf("%lld\n", res ); } return 0; }