P5769 [JSOI2016]飞机调度

1|0P5769 [JSOI2016]飞机调度

1|1题目描述:

Link

1|2题目分析:

上一次见最小链覆盖还是在上次

这个题的建模也是比较的神奇。(就我想怎么把点连起来是吧

如果说当前的飞机在飞完 i 条航线之后,可以接着飞 j 条航线,那么我们就从 ij 连一条有向边。

这样的话我们就可以得到一个 DAG,而我们的目标就是用尽可能少的飞机飞完所有的航线。

就是一个 DAG 上的最小路径覆盖的模型。

具体来说,就是把一个点拆成两个点,如果原图中存在 xy 的边,那么就从 x1y2

那么最小路径覆盖 = n - 二分图最大匹配数。(是时候把网络流 24 题过一遍了

那么剩下的问题就是如何判断飞完 i 条航线,能不能飞 j 条线的问题。

先 Floyd 预处理距离。那么就很好判断了。

1|3Code:

//editor : DRYAYST //Wo shi ge da SHA BI #include<bits/stdc++.h> #define g() getchar() #define il inline #define ull unsigned long long #define eps 1e-10 #define ll long long #define pa pair<int, int> #define for_1(i, n) for(int i = 1; i <= (n); ++i) #define for_0(i, n) for(int i = 0; i < (n); ++i) #define for_xy(i, x, y) for(int i = (x); i <= (y); ++i) #define for_yx(i, y, x) for(int i = (y); i >= (x); --i) #define for_edge(i, x) for(int i = head[x]; i; i = nxt[i]) #define int long long #define DB double #define ls (p<<1) #define rs (p<<1|1) #define m_p make_pair #define fi first #define se second using namespace std; const int N = 1e6 + 10, INF = 0x7f7f7f7f, mod = 1e9 + 7; il int qpow(int x, int k) {int ans = 1; while(k) {if(k & 1) ans = ans * x % mod; x = x * x % mod; k >>= 1; } return ans; } il int Add(int x, int y) {return (x += y) %= mod;} il int Del(int x, int y) {return (x = x - y + mod) % mod;} il int Mul(int x, int y) {return x * y % mod;} il int inv(int x) {return qpow(x, mod - 2); } inline int re() { int x = 0, p = 1; char ch = getchar(); while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();} while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * p; } int head[N], ver[N], edge[N], tot = 1, nxt[N]; il void add(int x, int y, int z) {ver[++tot] = y; nxt[tot] = head[x]; head[x] = tot; edge[tot] = z;} il void addedge(int x, int y, int z) {add(x, y, z); add(y, x, 0); } int n, m, s, t; int dep[N], now[N], a[N], dis[600][600], T[600][600]; struct Node{int x, y, d; } que[N]; queue<int> q; bool bfs() { while(q.size()) q.pop(); memset(dep, 0, sizeof(dep)); q.push(s); now[s] = head[s]; dep[s] = 1; while(q.size()) { int x = q.front(); q.pop(); for_edge(i, x) { int y = ver[i], z = edge[i]; if(!dep[y] and z) { now[y] = head[y]; dep[y] = dep[x] + 1; q.push(y); if(y == t) return 1; } } } return 0; } int dinic(int x, int flow) { if(x == t) return flow; int res = flow, k; for(int i = now[x]; i and res; i = nxt[i]){ int y = ver[i], z = edge[i]; if(dep[y] == dep[x] + 1 and z) { k = dinic(y, min(res, z)); if(!k) dep[y] = 0; edge[i] -= k; edge[i ^ 1] += k; res -= k; } now[x] = i; } return flow - res; } signed main() { freopen("summer.in","r",stdin); freopen("summer.out","w",stdout); n = re(), m = re(); for_1(i, n) a[i] = re(); s = 2 * m + 1, t = s + 1; for_1(i, n) for_1(j, n) {T[i][j] = re(); if(i != j) dis[i][j] = T[i][j] + a[j];} for_1(k, n) for_1(i, n) for_1(j, n) dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]); for_1(i, m) {que[i].x = re(), que[i].y = re(), que[i].d = re(); addedge(s, i, 1); addedge(i+m, t, 1); } for_1(i, m) for_1(j, m) {if(que[i].d + T[que[i].x][que[i].y] + a[que[i].y] + dis[que[i].y][que[j].x] <= que[j].d) addedge(i, j + m, 1); } int flow = 0, maxflow = 0; while(bfs()) while(flow = dinic(s, INF)) maxflow += flow; cout<<m - maxflow<<endl; }

__EOF__

本文作者Zwaire
本文链接https://www.cnblogs.com/Zwaire/p/16102325.html
关于博主:这个世界除了你,都知道我喜欢你
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Zwaire  阅读(74)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示