NC237204. 拯救萝莉(hard version)
描述
输入描述
第一行输入两个正整数表示城堡的数目以及单向运兵路线的数目。接下来行,每行输入三个非负整数表示从号城堡到号城堡的防御力,敌人总数,以及人口数。接下来行,每行输入两个正整数表示一条单向运兵线路。输入保证这些运兵线路构成一个DAG图,且从号城堡可到达所有城堡。
输出描述
仅一行一个整数,表示清楚姐姐一开始在号城堡中训练多少群友才能达成目标。
示例1
输入:
3 2 0 1 99 100 100 0 1 2 2 3
输出:
3
说明:
示例2
输入:
2 1 100 1 0 1 2
输出:
100
说明:
城堡的防御力为,需要至少人同时进攻才能攻打城堡。示例3
输入:
2 1 1 100 0 1 2
输出:
101
说明:
注意至少需要人存活才能占领城堡。示例4
输入:
10 9 5 7 6 0 9 5 9 2 2 8 7 9 10 2 0 4 3 5 4 10 8 9 8 8 1 2 8 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10
输出:
14
示例5
输入:
4 4 60 50 100 50 60 100 210 210 0 1 2 1 3 2 4 3 4
输出:
121
说明:
示例6
输入:
12 15 93474 10128 65752 65221 6983 41034 82452 34722 48764 21423 41519 59398 760 34788 24645 51178 9985 15211 52050 76240 64792 20318 16102 23494 90614 48972 68565 4694 22617 70520 76983 90440 76132 1 2 8 9 1 4 1 10 1 3 1 4 4 5 1 10 5 11 11 12 4 6 6 7 7 8 1 9 3 6
输出:
331761
C++(g++ 7.5.0) 解法, 执行用时: 11ms, 内存消耗: 604K, 提交时间: 2022-10-20 11:47:18
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std ; using ll = long long ; const int N = 20000,M = 2 * N ; const int INF = 1e9 ; int n,m,S,T ; int h[N],e[M],f[M],ne[M],idx; int q[N],dep[N],cur[N] ; // cur[]是为了使用当前弧优化,起名dep也是为了避免和dfs的d重名 void add(int a,int b,int c){ // 加边 e[idx] = b,f[idx] = c,ne[idx] = h[a],h[a] = idx ++ ; e[idx] = a,f[idx] = 0 ,ne[idx]= h[b],h[b] = idx ++ ; } bool bfs(){ // bfs int hh = 0 ,tt = 0 ; for(int i = 0 ; i <= T ; i++){ cur[i] = h[i] ; dep[i] = INF ; } q[0] = S,dep[S] = 0 ; while(hh <= tt){ int t = q[hh++] ; for(int i = h[t] ; ~ i ; i = ne[i]){ int j = e[i] ; if(dep[j] == INF && f[i]){ dep[j] = dep[t] + 1 ; q[++tt] = j; } } } if(dep[T] == INF) return 0; return 1 ; } int dfs(int u,int d){ if(u == T) return d; int used = 0 ; // 以及用过的流量 for(int i = cur[u] ; ~ i ; i = ne[i]){ // 当前弧优化 cur[u] = i ; int j = e[i] ; if(dep[j] == dep[u] + 1 && f[i]){ int nd ; if(nd = dfs(j,min(f[i],d-used))){ f[i] -= nd ; f[i^1] += nd ; used += nd ; if(used == d) break ; // 当用过的等于当前点,返回 } } } return used ; } ll dinic(){ ll res = 0,t ; while(bfs()) while(t = dfs(S,INF)) res += t ; return res ; } int main(){ scanf("%d%d",&n,&m) ; S = 0,T = 2 * n + 1 ; fill(h,h+T+1,-1) ; ll ans = 0 ; for(int i = 2 ; i <= n ; i ++){ int d,a,p ; scanf("%d%d%d",&d,&a,&p) ; int tot = max(a+1,d) ; add(S,i,tot - a + p) ; add(i+n,T,tot) ; ans += tot ; } for(int i = 1 ; i <= m ; i ++){ int a,b ; scanf("%d%d",&a,&b) ; add(a+n,b+n,INF) ; add(a,b+n,INF) ; } printf("%lld\n",ans - dinic()) ; return 0 ; }
C++ 解法, 执行用时: 12ms, 内存消耗: 948K, 提交时间: 2022-06-02 09:46:18
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 50010, M = (N + 125003) * 2, INF = 2147483647; int n, m, S, T; int h[N], e[M], f[M], ne[M], idx; int q[N], d[N], cur[N], A[N]; void add(int a, int b, int c) { e[idx] = b, f[idx] = c, ne[idx] = h[a], h[a] = idx ++ ; e[idx] = a, f[idx] = 0, ne[idx] = h[b], h[b] = idx ++ ; } bool bfs() { int hh = 0, tt = 0; memset(d, -1, sizeof d); q[0] = S, d[S] = 0, cur[S] = h[S]; while (hh <= tt) { int t = q[hh ++ ]; for (int i = h[t]; ~i; i = ne[i]) { int ver = e[i]; if (d[ver] == -1 && f[i]) { d[ver] = d[t] + 1; cur[ver] = h[ver]; if (ver == T) return true; q[ ++ tt] = ver; } } } return false; } int find(int u, int limit) { if (u == T) return limit; int flow = 0; for (int i = cur[u]; ~i && flow < limit; i = ne[i]) { cur[u] = i; int ver = e[i]; if (d[ver] == d[u] + 1 && f[i]) { int t = find(ver, min(f[i], limit - flow)); if (!t) d[ver] = -1; f[i] -= t, f[i ^ 1] += t, flow += t; } } return flow; } int dinic() { int r = 0, flow; while (bfs()) while (flow = find(S, INF)) r += flow; return r; } int main() { int sum=0; scanf("%d%d", &n, &m); S = 0, T = 2*n + 1; memset(h, -1, sizeof h); int x,a,b; for(int i=2;i<=n;i++) { cin>>x>>a>>b; add(S,i,max(1,x-a)+b); add(i+n,T,max(x,a+1)); sum+=max(x,a+1); } for(int i=1;i<=m;i++) { cin>>a>>b; add(a+n,b+n,1e9); add(a,b+n,1e9); } cout<<sum-dinic()<<endl; return 0; }